Javascript Promise.all中的setState钩子仅更新组件状态的最后一个元素

Javascript Promise.all中的setState钩子仅更新组件状态的最后一个元素,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,下面是程序和代码 我的组件的状态是一个TODO数组,通过useStatehook创建和更新。每个todo都可以通过自己的“保存”按钮进行编辑和保存,该按钮调用saveTodoasync函数 我正在尝试实现一个Save All按钮,该按钮将为承诺中的每个todo调用saveTodo函数。All-请参阅下面的handleOnSaveAllClicked 现在只更新最后一个todo。有什么线索可以全部更新吗 多谢各位 async function stall(stallTime = 3000) {

下面是程序和代码

我的组件的状态是一个TODO数组,通过
useState
hook创建和更新。每个todo都可以通过自己的“保存”按钮进行编辑和保存,该按钮调用
saveTodo
async函数

我正在尝试实现一个Save All按钮,该按钮将为
承诺中的每个todo调用saveTodo函数。All
-请参阅下面的
handleOnSaveAllClicked

现在只更新最后一个todo。有什么线索可以全部更新吗

多谢各位

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"));
异步函数暂停(暂停时间=3000){ 等待新的承诺(resolve=>setTimeout(resolve,stallTime)); } 常量Todo=({Todo,onFormChanged})=>{ const onChange=(键)=>{ return(e)=>onFormChanged(todo.id,{[key]:e.target.value}); }; 返回( 名字

); }; 常量应用=()=>{ const initDate=新日期() 常量initialTodos=[ {id:1,名称:“Todo 1”,时间:initDate}, {id:2,名称:“Todo 2”,时间:initDate} ]; const[todos,setTodos]=React.useState(initialTodos); const saveTodo=async(todo)=>{ //模拟异步http调用 等待摊位(1000) const newTodo={…todo,{time:new Date()}; setTodos(todos.map((t)=>(t.id==newTodo.id?newTodo:t)); }; const handleOnSaveAllClicked=async()=>{ 等待Promise.all(todos.map(t=>saveTodo(t))) } const handleon saveclicked=async(id)=>{ const todo=todos.find((t)=>t.id==id); 等待保存todo(todo) }; 常量handleFormChange=(id,数据)=>{ const todo=todos.find((t)=>t.id==id); 常数newTodo={…todo,…data}; setTodos(todos.map((t)=>(t.id==id?newTodo:t)); }; 返回( { e、 预防默认值(); handleOnSaveAllClicked(); }} >拯救一切 {todos.map((t)=>{ 返回( e、 preventDefault()}> {t.name}持续保存在{t.time.toLocaleString()上

{ e、 预防默认值(); handleon(t.id); }} > 拯救 ); })} ); }; render(,document.getElementById(“根”));
问题在于您使用的是创建函数时存在的
TODO
,而不是最新的
TODO
。因此,您最终会覆盖在此期间所做的任何更改。要使用最新版本,请使用setTodos的函数版本:

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

您正在通过闭包捕获TODO,因此saveTodo(即使是最后一个)在更新之前获得对
TODO
的引用。有趣的是,我从未见过此函数版本。为什么这不是默认值?它将防止所有陈旧的国家问题?非常感谢。