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

报错信息:
image.png

代码:

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>
  )
}

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

阅读 2.3k
2 个回答

这种写法在 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>
  )
}

建议先看一下 react

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题