如何在 MERN 应用程序中添加新待办事项后立即更新 UI,而不刷新页面?

问题描述 投票:0回答:1

Body:我正在开发一个 MERN stack todo 应用程序,并面临一个问题,即新添加的待办事项不会立即出现在 UI 中。新的待办事项仅在我刷新页面后才会显示。

问题:

通过单击“添加”按钮添加新的待办事项后,除非我手动刷新页面,否则该待办事项不会出现在 UI 中。我正在使用

setTodos
更新
TodoContext
中的状态,但新添加的待办事项不会立即反映在 UI 中。

预期行为:

我希望新添加的待办事项在单击“添加”按钮后立即显示在 UI 中,而不需要刷新页面。

const TodoContext = createContext();

export const TodoProvider = ({ children }) => {
  const [todos, setTodos] = useState([]);

  const addTodos = async (title) => {
    try {
      const response = await axios.post('/api/todos/addTodo', { title });
      // Updating the state with the newly added todo
      setTodos((prev) => [...prev, response.data.data]);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <TodoContext.Provider value={{ todos, addTodos }}>
      {children}
    </TodoContext.Provider>
  );
};


const Add = () => {
  const { addTodos } = useTodo();
  const [input, setInput] = useState("");

  const handleAdd = async () => {
    if (input.trim()) {
      await addTodos(input);  // Adding new todo
      setInput("");  // Resetting input field
    }
  };

  return <button onClick={handleAdd}>Add</button>;
};

const Read = () => {
  const { todos } = useTodo();

  return (
    <div>
      {todos.map(todo => (
        <div key={todo._id}>{todo.title}</div>  // Displaying todos
      ))}
    </div>
  );
};
javascript reactjs react-state
1个回答
0
投票

出现此行为的原因是您使用 setTodos 进行的状态更新没有立即反映在 UI 中。这是因为 React 的状态更新是异步的,并且 UI 重新渲染发生在状态更新之后。 要解决此问题并使新添加的待办事项立即出现在 UI 中,您可以使用以下方法:

乐观的用户界面更新: 您可以乐观地更新状态,即在用户单击“添加”按钮后立即更新状态,而不是等待 API 响应来更新状态。这将使新的待办事项立即出现在 UI 中,然后您可以使用 API 响应中的实际数据更新状态。

const TodoContext = createContext();

export const TodoProvider = ({ children }) => {
  const [todos, setTodos] = useState([]);

  const addTodos = async (title) => {
    try {
      setTodos((prev) => [...prev, { _id: Math.random().toString(), title, completed: false }]);

      const response = await axios.post('/api/todos/addTodo', { title });
      // update with actual one
      setTodos((prev) =>
        prev.map((todo) =>
          todo._id === response.data.data._id ? response.data.data : todo
        )
      );
    } catch (error) {
      console.error(error);
      // revert the change if it fails
      setTodos((prev) => prev.filter((todo) => todo._id !== response.data.data._id));
    }
  };

  return (
    <TodoContext.Provider value={{ todos, addTodos }}>
      {children}
    </TodoContext.Provider>
  );
};

const Add = () => {
  const { addTodos } = useTodo();
  const [input, setInput] = useState("");

  const handleAdd = async () => {
    if (input.trim()) {
      await addTodos(input);
      setInput("");
    }
  };

  return <button onClick={handleAdd}>Add</button>;
};

const Read = () => {
  const { todos } = useTodo();

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo._id}>{todo.title}</div>
      ))}
    </div>
  );
};

© www.soinside.com 2019 - 2024. All rights reserved.