即使状态没有改变,为啥 setState 会导致太多的重新渲染错误

Posted

技术标签:

【中文标题】即使状态没有改变,为啥 setState 会导致太多的重新渲染错误【英文标题】:Why setState causes too many rerender Error even though the state hasn't changed即使状态没有改变,为什么 setState 会导致太多的重新渲染错误 【发布时间】:2021-10-21 21:52:52 【问题描述】:

您好,我现在正在学习 React,但遇到了状态问题..

我知道当状态改变时,组件会重新渲染,UseEffect 中的代码只运行一次。 但是我无法准确解释为什么我在 JSX 或渲染语法中编写 setState 时会发生无限渲染。

以下代码导致无限重新渲染

import React,  useState, useEffect  from 'react'

const index = () => 
  const [active, setActive] = useState(false);
  console.log("render", active);
  setActive(false);
  
  return (
    <div>
      
    </div>
  )


export default index

但是下面的代码即使一直调用setState也没问题。

import React,  useState, useEffect  from 'react'

const index = () => 
  const [active, setActive] = useState(false);
  console.log("render", active);

  useEffect(() => 
    setInterval(()=>
      console.log("run")
      setActive(true)
    ,0);
  , [])
  
  return (
    <div>
      
    </div>
  )


无论状态值如何,setState 都会触发重新渲染吗? 我想知道在 useEffect 之外使用 setState 会导致错误的确切原因。

【问题讨论】:

这个好像和组件生命周期有关;第一个示例在渲染之前运行setActive,此时循环可以被 React 中止或重新启动,而第二个示例在渲染完成后调用它,此时 React 能够更好地避免不必要的重新渲染 这能回答你的问题吗? Difference between with and without useEffect in react functional component 【参考方案1】:

发生这种情况是因为,在第一种情况下,当未使用 useEffect 时, 您在声明后立即更新您的状态。 即使您再次将状态设置为 false,但对于响应,状态已更新。 React 的第一条经验法则是,如果发生状态更新,组件将重新渲染。

这就是您获得无限重新渲染的原因。

您的代码遵循以下流程:

    声明状态变量并将值传递为 false 将状态更新为 false 状态已更新,因此组件重新呈现。 再次执行第 1 步。

在第二种情况下,使用了useEffect,你的状态只有在组件被挂载时才会更新,这意味着之后任何状态更新都不会触发你的useEffect。

【讨论】:

“只有当组件被挂载时,你的状态才会更新” - 在useEffect 内部,有setInterval 调用,它会定期调用setActive(true)。为什么每次调用 setActive(true) 时组件不重新渲染?原因是,如果旧状态和以前的状态相同,react 将退出状态更新并且不会重新渲染组件但是,如下面的答案中所述,React 可能需要在退出之前再次渲染组件状态更新。【参考方案2】:

基于 React 文档:https://reactjs.org/docs/hooks-reference.html#usestate

setState 函数用于更新状态。它接受一个新的状态值并将组件的重新渲染排入队列。

还有一个补充:https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update

如果您将 State Hook 更新为与当前状态相同的值,React 将退出而不渲染子级或触发效果。 (React 使用 Object.is 比较算法。)请注意,React 可能仍需要在退出之前再次渲染该特定组件。

这是重要的部分:React 可能仍需要在退出之前再次渲染该特定组件

所以是的,即使值相同,组件仍可能重新渲染。

【讨论】:

如果你在setTimeout(...):setTimeout(() =&gt; setActive(false), 0) 中封装setActive 调用,那么React 会按预期退出状态更新;仍然不确定为什么 React 没有在函数组件的顶层调用 setActive 退出

以上是关于即使状态没有改变,为啥 setState 会导致太多的重新渲染错误的主要内容,如果未能解决你的问题,请参考以下文章

更新状态 - 为啥在调用 setState 时创建新的状态副本?

ReactJS:为啥我不应该改变嵌套状态?

为啥我的状态值即使在改变状态后也没有改变? [复制]

为啥即使在有状态小部件中使用 setstate 也无法获取更新的变量。因为我想在新的 TabBar 选项上更新我的 Container

即使数据没有改变,我可以用 setState 强制重新渲染吗?我的 GUI 不会更新?

为啥小部件的状态在颤动时没有改变?