使用useReducer和useContext开发Todo应用时更新功能失效求助
Todo应用更新功能失效问题修复
问题描述
使用useReducer和useContext开发Todo应用时,更新功能无法正常工作:点击编辑按钮后输入框会填充选中的待办内容,但修改内容后点击更新按钮毫无反应。
相关代码
App.jsx
export default function App() { const { dispatch, state } = useContext(todoContext); const [todo, setTodo] = useState(""); const [isEditing, setIsEditing] = useState(false); const [selectedTodo, setSelectedTodo] = useState(""); const handleSubmit = (e) => { const id = uuidv4(); e.preventDefault(); if (!isEditing) { dispatch({ type: "ADD_TODO", payload: { id: id, text: todo }, }); setTodo(""); } else { dispatch({ type: "UPDATE_TODO", payload: selectedTodo, }); setIsEditing(false); setTodo(""); } }; const handleEdit = (val) => { setIsEditing(true); const item = state.todos.find((todo) => todo.id === val.id); setTodo(item.text); setSelectedTodo(item); }; return ( <div className="App"> <br /> <h1>Hello World This is Todo App</h1> <br /> <form onSubmit={handleSubmit}> <input value={todo} onChange={(e) => setTodo(e.target.value)} type="text" placeholder="Enter a todo" /> <button>{isEditing ? "Update" : "Submit"}</button> </form> {state.todos.map((item) => ( <div key={item.id} className="todoitem"> <p onClick={() => dispatch({ type: "TOGGLE_TODO", payload: item.id })} style={{ cursor: "pointer", textDecoration: item.completed ? "line-through" : "", }} > {item.text} </p> <span onClick={() => dispatch({ type: "REMOVE_TODO", payload: item.id })} > × </span> <button onClick={() => handleEdit(item)}>Edit</button> </div> ))} </div> ); }
todoReducer.jsx
export const INITIAL_STATE = { todos: [], updated: [], }; export const reducer = (state, action) => { switch (action.type) { case "ADD_TODO": return { ...state, todos: [...state.todos, action.payload], }; case "REMOVE_TODO": { return { ...state, todos: state.todos.filter((item) => item.id !== action.payload), }; } case "TOGGLE_TODO": return { ...state, todos: state.todos.map((todo) => todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo ), }; case "UPDATE_TODO": return { ...state, todos: state.todos.map((todo) => { if (todo.id === action.payload.id) { return action.payload; } return todo; }), }; default: return state; } };
问题原因
更新功能失效的核心原因是:修改输入框内容时,更新的是todo状态,但提交更新时传给dispatch的payload依然是编辑前存储的selectedTodo(旧数据),并没有把新输入的文本同步进去。reducer拿到的还是旧的todo对象,自然不会有任何变化。
修复方案
修改handleSubmit函数里的更新逻辑,基于selectedTodo的id和新输入的todo文本,创建一个包含最新内容的对象作为payload:
// 替换handleSubmit中的else块 else { dispatch({ type: "UPDATE_TODO", payload: { ...selectedTodo, text: todo }, }); setIsEditing(false); setTodo(""); }
这样reducer就能拿到带有最新文本的todo对象,找到对应id的项进行替换,更新功能即可正常工作。
内容的提问来源于stack exchange,提问作者Bipin Bhandari
相关产品推荐
相关产品推荐

