对数组使用 setState 时的无限循环

Posted

技术标签:

【中文标题】对数组使用 setState 时的无限循环【英文标题】:Infinite Loop when using setState for array 【发布时间】:2021-02-13 03:12:35 【问题描述】:

我想在一个数组中存储 4 个“hi”。而不是:

strArr.push('hi');
strArr.push('hi');
strArr.push('hi');
strArr.push('hi');

我这样做了:

for(let i = 0; i<4; i++)
   setStrArr([...strArr, "hi"])

但是,我收到此错误:错误:重新渲染过多。 React 限制渲染次数以防止无限循环

我不知道出了什么问题,我想知道当 i=3 时它是否没有达到。所以我做了一个检查:

for(let i = 0; i<4; i++)
   setStrArr([...strArr, "hi"])
   if(i==3)
      console.log("done")
   

'i'的值确实达到了3,但是为什么我的代码又运行了?

这是我的代码:

function MyApp()
  const [strArr, setStrArr] = useState([]);
  for(let i = 0; i<4; i++)
       setStrArr([...strArr, "hi"])
       if(i==3)
          console.log("done")
       
          
  return(
    <div>
    </div>
  )

【问题讨论】:

你在 JSX 的什么地方做这个 for 循环?你在用钩子吗?钩子的依赖是什么? @Amir-Mousavi 添加了我的代码 【参考方案1】:

添加到其他答案,因为您正在执行 同步 代码,我将使用 useLayoutEffect 挂钩。 useLayoutEffect 运行,React 等待它完成。这对于响应等待来说很好,因为代码都是同步的,并且它可以防止您的组件在屏幕上“闪烁”,因为在渲染完成后会调用 useEffect。

function MyApp()
  const [strArr, setStrArr] = useState([]);

  useLayoutEffect(() => 
     let fourHiArray = [];

    for(let i = 0; i<4; i++)
       fourHiArray = ([...fourHiArray, "hi"])
       if(i==3)
          console.log("done")
       
     

    setStrArr(fourHiArray);
  , []);
       
  return(
    <div>
    </div>
  )

【讨论】:

非常感谢。我之前还没有使用过useLayoutEffect,将阅读它【参考方案2】:

在重新渲染时调用整个函数 MyApp,因此在每次重新渲染时,您的循环都会重新开始。如果您只想调用一次,请在 useEffect 中调用它。像这样

useEffect(() => *your code here*, []

使用空数组作为第二个参数的 useEffect 仅在第一次渲染时调用。

如果你想设置你的初始状态,我建议你在 useState(['hi','hi','hi','hi'])

【讨论】:

【参考方案3】:

我相信您可能会遇到问题,因为调用 setStringArray 是一种“副作用”。

这将导致函数组件无限重新渲染,因为钩子已经更新了组件的状态,导致重新渲染,然后无限更新状态。

基本上,您不应该尝试在同一行中同时读取和更新strArray

您应该只在完全填充数组后调用setStrArr一次

我认为您还应该考虑使用 useEffect 钩子来实现这样的行为。

它传递的最后一个参数告诉 React 仅在给定的参数(在本例中为 strArray)发生更改时才运行此 useEffect 挂钩内的代码。

当您希望在您的组件中具有“副作用”时,此钩子设计。

所以也许你可以尝试一些类似的方法来防止你的无限重新渲染:

function MyApp()
  const [strArr, setStrArr] = useState([]);

  useEffect(() => 
     const fourHiArray = [];

    for(let i = 0; i<4; i++)
       fourHiArray = ([...fourHiArray, "hi"])
       if(i==3)
          console.log("done")
       
     

    setStrArr(fourHiArray);
  , [strArr]);
       
  return(
    <div>
    </div>
  )

【讨论】:

谢谢。但是你能否进一步解释一下为什么改变状态会导致重新渲染?一直以来,我认为只有使用像 useEffect 这样的钩子才会导致无限地重新渲染。 别担心!希望这可以帮助。因此,当状态更新时,React 组件将总是重新渲染!这是一个“这就是 React 是如何工作的”的案例。这里有一篇很酷的博客文章:lucybain.com/blog/2017/react-js-when-to-rerender/…。

以上是关于对数组使用 setState 时的无限循环的主要内容,如果未能解决你的问题,请参考以下文章

在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState。 React 限制嵌套更新的数量以防止无限循环

确定文件大小时的Python无限循环

使用Vue组件渲染功能时的无限循环

在c ++ 11中使用异常时的无限循环

使用 OnetoMany 和 ManytoOne 映射时的无限递归循环(双向)

React Redux:调度时的无限循环