【问题标题】:setState in async function异步函数中的 setState
【发布时间】:2021-10-12 06:24:28
【问题描述】:

假设以下示例:

const example = () => {
    const [objects, setObjects] = useState([])

    const asyncFunction = async() => {

         // This will trigger the API and assume it takes around 10 seconds to run
         let result = api.fetchObjects().then((result) => {
             // Here, setObjects will be called with the value it had at the moment the function started executing, not the actual value
             setObjects(result)
         }
    }
}

我的问题是,执行 setObjects(result) 和使用更新状态的最佳方法是什么?假设用户可以在这 10 秒内通过应用中的不同方式将对象添加到该状态。

我找到了一个使用 useEffect 的解决方案,如下所示:

// Instead of setObjects(result)
const [updateObjects, setUpdateObjects] = useState(null)
setUpdateObjects(result)

useEffect(() => {
if (updateObjects !== null) {
setObjects(updateObjects)
setUpdateObjects(null)
}

【问题讨论】:

  • const result = await api.fetchObjects(); setObjects(result); 呢?
  • 这将在每次重新渲染时运行。我需要它在一个函数中

标签: javascript reactjs react-hooks use-state


【解决方案1】:

您应该使用功能状态更新来访问和更新之前的状态。

functional updates

注意

与类组件中的setState 方法不同,useState 不会自动合并更新对象。你可以复制这个 通过将函数更新器形式与对象传播相结合的行为 语法:

const [state, setState] = useState({});
setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

使用承诺链

const asyncFunction = () => {
  api.fetchObjects()
    .then((result) => {
      setObjects(objects => [
        ...objects, // <-- shallow copy previous state array
        result,     // <-- append new state
      ]);
    });
}

或使用async/await

const asyncFunction = async () => {
  const result = await api.fetchObjects();
  setObjects(objects => [
    ...objects, // <-- shallow copy previous state array
    result,     // <-- append new state
  ]);
}

根据 实际 状态形状和 result 值,您的实际状态更新功能可能会根据您的具体需求而略有不同。

【讨论】:

  • 您对扩展运算符是正确的,但“对象”仍然是未更新的值。假设在 API 运行时,用户可以将 10 个对象添加到该列表中。 setObjects 将简单地删除在函数执行期间添加的任何条目
  • @CristianNicolaePerjescu objects 将是处理状态更新时之前的状态值。它将是更新的最新状态,包括在调用 asyncFunction 和 Promise 解决之间的所有先前更新。您将功能更新与 setObjects({ ...objects, ...result }) 混淆了,由于 JS 外壳的工作方式,它可能会覆盖任何以前的状态更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 2020-03-19
  • 2020-01-31
相关资源
最近更新 更多