You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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 })}
          >
            &times;
          </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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 17:50:36