在 useEffect 中处理 forEach 后调用 setstate

Posted

技术标签:

【中文标题】在 useEffect 中处理 forEach 后调用 setstate【英文标题】:Calling setstate after processing forEach within useEffect 【发布时间】:2021-09-22 21:16:20 【问题描述】:

我正在尝试在 useEffect 上处理一些 api 数据,在处理数据时我需要将其设置为各种状态,在处理数据时,由于某些原因 useEffect 被无限触发。尽管从类组件中我知道 setState 是一个不等待 forEach 完成的异步操作。我们有针对功能组件的解决方法吗?

  useEffect(() => 
    const apiResponse = fetchAppName();  
    apiResponse.then(
        (response) => 
          // if (response.statusCode === '200' && response.status.statusType === 'SUCCESS' && response.data) 
            const dataFields = ;
            const appNameValues = [];
            dummyData.data.forEach((ele) => 
              const workFlowIds = [];
              ele.workflowConfigs.forEach((wc) => 
                workFlowIds.push(wc.workflowId);
              )
              dataFields[ele.name] = workFlowIds;
            );
            Object.keys(dataFields).forEach((k) => 
              appNameValues.push(k);
            );
            setAppData(dataFields);
            setDropDownOptions(
              ...dropDownOptions,
              appName: appNameValues,
            );
          // 
      ).catch((e)=>
        console.log('Failed to fetchAppNames due to: ', e);
      );
  ,[setDropDownOptions, dropDownOptions]);

【问题讨论】:

不要把setter放在依赖数组中 即使在那之后它也被无限调用@Jazz 您希望效果何时运行? 你设置它,然后在设置它时调用它,所以它正在创建一个循环我认为你应该删除这两个依赖项 @DrewReese:我想在第一个 forEach 循环完成后运行这个效果,基本上在所有 forEach 完成时调用 setDropDownOptions 【参考方案1】:

问题

不要使用由效果更新的依赖项。换句话说,dropDownOptions 是一个依赖,效果会更新它,从而创建一个渲染循环。

解决方案

状态更新函数是稳定的,所以没必要,用一个函数状态更新来移除另一个dropDownOptions依赖。

useState

注意

React 保证 setState 函数的身份是稳定的,不会 更改重新渲染。这就是为什么从 useEffect 中省略是安全的 或者 useCallback 依赖列表。

useEffect(() => 
  const apiResponse = fetchAppName();  
  apiResponse.then(
    (response) => 
      // if (response.statusCode === '200' && response.status.statusType === 'SUCCESS' && response.data) 
        const dataFields = ;
        const appNameValues = [];
        dummyData.data.forEach((ele) => 
          const workFlowIds = [];
          ele.workflowConfigs.forEach((wc) => 
            workFlowIds.push(wc.workflowId);
          )
          dataFields[ele.name] = workFlowIds;
        );
        Object.keys(dataFields).forEach((k) => 
          appNameValues.push(k);
        );
        setAppData(dataFields);
        setDropDownOptions(dropDownOptions => (
          ...dropDownOptions,
          appName: appNameValues,
        ));
      // 
    ).catch((e)=>
      console.log('Failed to fetchAppNames due to: ', e);
    );
,[]); // will run on mount, add other dependency triggers if needed.

【讨论】:

我曾经在某处读到 setState 和 forEach 循环一样是异步的。我有点想,也许在第一次 forEach 的执行过程中调用了 setDropDownOptions,然后再一次 forEach 循环继续执行剩下的上下文,从而形成了一个渲染循环。 @DrewResse @AshishBairwa setStateuseState 更新函数是完全同步的函数,它们将要更新的状态排入队列(即“请求”)。 React 排队状态更新异步处理。 forEach 循环也是同步的。 @DrewResse github.com/facebook/react/issues/11527#issuecomment-360199710

以上是关于在 useEffect 中处理 forEach 后调用 setstate的主要内容,如果未能解决你的问题,请参考以下文章

如何在 useEffect 挂钩中使用 Promise.all 获取所有数据?

在 ReactJS 的 useEffect 中定义后 useEffect 值保持不变

useState 在 useEffect 中定义后保持初始状态

React - 是不是在 useEffect 中调用 API

带有 socket.io 状态的 UseEffect 钩子在套接字处理程序中不持久

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