在异步函数中正确使用 useEffect 和 useState [重复]

Posted

技术标签:

【中文标题】在异步函数中正确使用 useEffect 和 useState [重复]【英文标题】:Proper use of useEffect with useState called within async function [duplicate] 【发布时间】:2021-12-20 00:59:14 【问题描述】:

致敬!

我正在尝试(并成功)在异步函数中复制一个数组。我正在使用这个数组来设置在 React 组件的顶层声明的数组的状态,如下所示:

  const [retrievedData, setRetrievedData] = useState([]);

  useEffect(() => 
    setRetrievedData;
  , [retrievedData]);

  async function fetchInfo() 
    const promiseData = await Promise.all(<My fetch links array>)
    );

    const dataInJson = await promiseData.map((resp) => resp.json());

    let actualData = [];

    for (let i = 0; i < dataInJson.length; i++) 
      const foo = await Promise.resolve(dataInJson[i]);
      actualData.push(foo);
    

    setRetrievedData(actualData);
  

  fetchInfo();

这段代码的问题在于它创建了一个无限循环的 setStates,即使我将 useEffect 第二个参数设置为一个空数组也是如此。我还尝试在调用 fetchInfo 函数时使用 async/await,但这当然只是返回另一个 Promise。在处理这个问题时,我还注意到 Promise.all 调用运行了两次。

感谢您花时间阅读此问题。

【问题讨论】:

【参考方案1】:

做这样的事情:

const [retrievedData, setRetrievedData] = useState( data: [] );

const fetchInfo = useCallback(async () => 
  // do your stuff here...

  setRetrievedData( data );
, []);

useEffect(() => 
  fetchInfo();
, [fetchInfo]);

如果您打算将数据追加retrievedData,那么您可以像这样调用setRetrievedData

setRetrievedData(prevState => (
  data: [...prevState.data, newData]
));

如果您仅在组件加载期间使用fetchInfo,您可以将其定义(不带useCallback)移动到您的useEffect,并将一个空的依赖数组传递给它,如the other answer 所示。

【讨论】:

这将导致无限循环,因为fetchInfo 是对函数的新引用,useEffect 将在每次调用fetchInfo 时运行,并且每个fetchInfo 将通过设置setState 导致重新渲染跨度> @Jan 是的,解决了这个问题。请参阅更新后的答案。【参考方案2】:

这是反应中的常见模式

const Component = () => 
    const [data, setData] = useState();
    useEffect(()=>
        const fetchData = async () => 
            const data = await fetch();
            setData(data);
        
        fetchData();
    , [])
    return <div>JSON.stringify(data)</div>


【讨论】:

这很好用,谢谢。由于数据是使用状态更新的,所以这不是一个真正的问题,但是这似乎是渲染两次的原因吗?即使我只是在 fetchData 函数中记录数据,我也会先得到 undefined,然后才是想要的结果 第一次组件在没有数据的情况下渲染(例如,您可以显示微调器)之后 useEffect 将运行并调用 fetch 并且当 promise 解决时它将调用 setState 调用 setState 后组件将使用数据更新这次 正常。调用 fetch 后,setData 再次渲染组件 在组件的第一次渲染中,数据未定义,您可以使用显示加载或类似的东西。这是一种常见的模式。这没什么好担心的,因为它不是不必要的渲染。

以上是关于在异步函数中正确使用 useEffect 和 useState [重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 useEffect 挂钩中取消所有异步/等待任务以防止反应中的内存泄漏的正确方法是啥?

在useEffect中创建一个异步函数,并在函数的while循环中使用await,似乎不起作用

如何取消 useEffect 清理函数中的所有订阅和异步任务?

React Native useEffect 在异步函数中的用法[重复]

将异步函数放入 useEffect 后出现错误

如何在 React 的 UseEffect() 中调用异步函数?