useEffect 的相互竞争

在 React 的项目中我们经常会使用 useEffect 这个hook 去处理组件中的 SideEffect,为确保的组件在每次渲染时都得到同样的数据,React 在开发模式下会对每个 useEffect 函数执行2 次。这种情况如果我们没有正确清除 useEffect 带来的 SideEffect 的话就会形成一种相互竞争 或者 Race Condition。比如下面的例子:

const Com = ({timeout, text}) => {
  const ref = useRef()
  useEffect(() => {
    setTimeout(() => {
      ref.textContent = text;
    }, timeout)
  }, [timeout])
  return (<div ref={ref}/>)
}

当父级组件传入不同的值 3000, 3000ms 和 2000,2000ms时,组件会先显示 2000ms 然后3000ms而不是我们设想的只显示2000ms。

解决上面问题的方式就是在 useEffect 被清除的时候我们也需要执行相应的函数清除 SideEffect。

const Com = ({timeout, text}) => {
  const ref = useRef()
  useEffect(() => {
-    setTimeout(() => {
+    const id = setTimeout(() => {
      ref.textContent = text;
    }, timeout)
+    return () => clearTimeout(id)
  }, [timeout])
  return (<div ref={ref}/>)
}