Reputation: 187
So I have this to-do list app and I'm working on editing the name of to-do.
When I click on button edit
I get the value of the name in input field, and when I type something in that field and press enter, it should change/update to-dos' name, but right now it is only adding new to-do.
Here is code I have so far that is working, I deleted all the unsuccessful attempts. I have no more ideas.
import React, { useRef, useReducer } from 'react'
function App() {
const inputRef = useRef<HTMLInputElement | any>(null)
const handleSubmit = (e: any) => {
e.preventDefault()
inputRef.current?.value !== "" && dispatch({ type: 'ADD_TODO', payload: inputRef.current?.value })
inputRef.current && (inputRef.current.value = "")
}
const [todo, dispatch] = useReducer((state: any, action: any): any => {
switch (action.type) {
case 'ADD_TODO':
return [...state, { id: state.length, name: action.payload, isCheck: false }]
case 'CHECK_TODO':
return state.filter((item: any, index: any): any => {
if (index === action.id) {
item.isCheck = !item.isCheck
}
return item
})
case 'DELETE_TODO':
return state.filter((item: any, index: any) => index !== action.id)
case 'EDIT_TODO':
inputRef.current.focus()
inputRef.current.value = action.payload
return state
}
}, [])
const todos = todo.map((item: any, index: number) => {
return (
<li key={index}>
<input type="checkbox" checked={item.isCheck} onChange={() => dispatch({ type: "CHECK_TODO", id: index })} />
{item.name}
<button onClick={() => dispatch({ type: 'EDIT_TODO', id: index, payload: item.name })}>edit</button>
<button onClick={() => dispatch({ type: "DELETE_TODO", id: index })}>x</button>
</li>
)
})
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder='Buy milk'
ref={inputRef}
/>
</form>
<ul>{todos}</ul>
</div>
)
}
export default App
EDIT
Also, new button can be added for submit editing instead of pressing enter, as an option.
Upvotes: 0
Views: 721
Reputation: 1292
You have to keep track of which id/index you are editing so that you can identify whether you are updating or adding value in state. Following code might help. I removed typescript though.
function App() {
const inputRef = React.useRef(null)
const [editingIndex, setEditingIndex] = React.useState(null)
const handleSubmit = (e) => {
e.preventDefault()
if(inputRef.current && inputRef.current.value !== ""){
dispatch({ type: 'ADD_TODO', payload: inputRef.current.value, id: editingIndex})
}
inputRef.current && (inputRef.current.value = "")
}
const [todo, dispatch] = React.useReducer((state, action) => {
switch (action.type) {
case 'ADD_TODO':
setEditingIndex(null)
const tempState = [...state]
if(action.id){
tempState[action.id] = { ...tempState[action.id], name: action.payload }
}
else{
tempState.push({ id: action.id || state.length, name: action.payload, isCheck: false })
}
return tempState
case 'CHECK_TODO':
return state.filter((item, index) => {
if (index === action.id) {
item.isCheck = !item.isCheck
}
return item
})
case 'DELETE_TODO':
return state.filter((item, index) => index !== action.id)
case 'EDIT_TODO':
inputRef.current.focus()
inputRef.current.value = action.payload
return state
}
}, [])
const todos = todo.map((item, index) => {
return (
<li key={index}>
<input type="checkbox" checked={item.isCheck} onChange={() => dispatch({ type: "CHECK_TODO", id: index })} />
{item.name}
<button onClick={() => {setEditingIndex(index); dispatch({ type: 'EDIT_TODO', id: index, payload: item.name })}}>edit</button>
<button onClick={() => dispatch({ type: "DELETE_TODO", id: index })}>x</button>
</li>
)
})
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder='Buy milk'
ref={inputRef}
/>
</form>
<ul>{todos}</ul>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 749
Even though you are populating the input with the todo's name when you click the edit button, in the end the onSubmit
is calling the handleSubmit
function which calls the ADD_TODO
reducer.
One thing you can do is set an "edit mode" flag, and change how handleSubmit does it's dispatching and make a new type like UPDATE_TODO
using the index. Or make that a new function and call the appropriate one based on the update flag, like so:
<form onSubmit={editMode ? handleEdit : handleSubmit}>
Upvotes: 1