React 警告:渲染其他组件时无法更新组件?

作者站长头像
站长
· 阅读数 15

报错信息:React 警告:渲染其他组件时无法更新组件?

代码:

function Answer (props) {
  const [countDown, setCountDown] = useState(3)
  if (countDown > 0) {
    setTimeout(() => {
      setCountDown(countDown - 1)
    }, 1000);
  } else {
    props.setStatus('guessing')
  }
  return (
    <Fragment>
      <div className="box" style={props.style}></div>
      <span className="num">{countDown}</span>
    </Fragment>
  )
}

问题描述:子组件是一个倒计时组件,当倒计时结束时,修改父组件的状态去渲染其他组件。请问要如何处理?

回复
1个回答
avatar
test
2024-07-16

这种写法在 React 中是不正确的,每次更新 state 时,函数组件都会重新执行一遍,父组件的状态更新也会导致 该组件 重新执行,所以你的实现有如下问题

  • 如果不是 countDown 引起的更新,不应该创建定时器
  • 如果在倒计时未完成的情况下,组件就被卸载了,但定时器并没有被清除,计时完成后任然会调用 setCountDown,导致 React 报异常

正确的实现需要用到 useEffect 来处理副作用 和 清除依赖,如下

function Answer (props) {
  const [countDown, setCountDown] = useState(3)

  useEffect(() => {
    let timer;
    if (countDown > 0) {
      timer = setTimeout(() => {
        setCountDown(countDown - 1)
      }, 1000);
    } else {
      props.setStatus('guessing')
    }

    return () => {
        // 组件卸载时,清除定时器
        if (timer) {
            clearTimeout(timer)
        }
    }
  }, [countDown])
  
  return (
    <Fragment>
      <div className="box" style={props.style}></div>
      <span className="num">{countDown}</span>
    </Fragment>
  )
}
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容