【问题标题】:setState hook in Promise.all only updates the last element of the component statePromise.all 中的 setState hook 只更新组件状态的最后一个元素
【发布时间】:2021-07-25 05:08:33
【问题描述】:

这是codepen 和下面的代码。

我的组件的状态是一个 todos 数组,它使用useState 钩子创建和更新。每个待办事项都可以通过调用saveTodo 异步函数的自己的保存按钮进行编辑和保存。

我正在尝试实现一个 Save All 按钮,该按钮将为 Promise.all 中的每个待办事项调用 saveTodo 函数 - 请参阅下面的 handleOnSaveAllClicked

现在只更新最后一个待办事项。有什么线索可以更新它们吗?

谢谢。

async function stall(stallTime = 3000) {
  await new Promise(resolve => setTimeout(resolve, stallTime));
}

const Todo = ({ todo, onFormChanged }) => {
  const onChange = (key) => {
    return (e) => onFormChanged(todo.id, { [key]: e.target.value });
  };
  return (
    <div>
      <label>
        <p>Name</p>
      </label>
      <input type="text" value={todo.name} onChange={onChange("name")} />
    </div>
  );
};

const App = () => {
  const initDate = new Date()
  const initialTodos = [
    { id: 1, name: "Todo 1", time: initDate},
    { id: 2, name: "Todo 2", time: initDate }
  ];

  const [todos, setTodos] = React.useState(initialTodos);

  const saveTodo = async (todo) => {
    //simulate async http call
    await stall(1000)

    const newTodo = { ...todo, ...{ time: new Date() } };
    setTodos(todos.map((t) => (t.id === newTodo.id ? newTodo : t)));
  };
  
  const handleOnSaveAllClicked = async () => {
    await Promise.all(todos.map(t => saveTodo(t)))
  }
  
  const handleOnSaveClicked = async (id) => {
    const todo = todos.find((t) => t.id === id);
    await saveTodo(todo)
  };
  
  const handleFormChange = (id, data) => {
    const todo = todos.find((t) => t.id === id);
    const newTodo = { ...todo, ...data };
    setTodos(todos.map((t) => (t.id === id ? newTodo : t)));
  };
  
  return (
    <div>
      <button type="button" onClick={(e) => {
                  e.preventDefault();
                  handleOnSaveAllClicked();
                }}
        >Save All</button>
      {todos.map((t) => {
        return (
          <div>
            <form onSubmit={(e) => e.preventDefault()}>
              <p>{t.name} lasted saved on {t.time.toLocaleString()}</p>
              <button
                type="button"
                onClick={(e) => {
                  e.preventDefault();
                  handleOnSaveClicked(t.id);
                }}
              >
                Save
              </button>
              <Todo todo={t} key={t.id} onFormChanged={handleFormChange} />
            </form>
          </div>
        );
      })}
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

【问题讨论】:

  • 您正在通过关闭捕获待办事项,因此 saveTodo(即使是最后一个)在更新前获得对 todos 的引用。

标签: javascript reactjs react-hooks


【解决方案1】:

问题是您使用的是创建函数时存在的todos,而不是最新的todos。因此,您最终会覆盖在此期间所做的任何更改。要使用最新的,请使用 setTodos 的函数版本:

setTodos(prev => prev.map((t) => (t.id === newTodo.id ? newTodo : t)));

【讨论】:

  • 有意思,没见过这个函数版本。为什么这不是默认值?它会防止所有过时的状态问题吗?谢谢
猜你喜欢
  • 2021-02-06
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多