React Hook的闭包陷阱

959 阅读1分钟

什么是闭包陷阱

了解闭包陷阱之前,我们要先知道函数式组件是怎么渲染的

所谓的闭包陷阱,就是在函数式组件中,我们拿不到通过useState定义的变量的最新值。

const App = ()=>{
  const [count,setCount] = useState(0)
  useEffect(()=>{
    const timeId = setInterval(()=>{
      console.log(count);
    },1000)
    return ()=>{clearInterval(timeId)}
  },[])
  return (
    <div>
    	<span>{count}</span>
      <button onClick={()=>{setCount(count+1)}}>ADD</button>
    </div>
  )
}

比如说,这段代码我们点击button,页面上渲染的count值是会增加,但控制台打印的值,始终会是0。

事实上,esLint也会报一个warning:

始终输出0的原因是,函数式组件每次渲染都会有自己的Effect函数和count值,我们依赖数组设为[],后面useEffect也并没有更新了,所以setInterval里读取的都是第一次渲染的count,也就是0。

解决方案

  1. 在依赖数组中加入count
useEffect(()=>{
    const timeId = setInterval(()=>{
      console.log(count);
    },1000)
    return ()=>{clearInterval(timeId)}
  },[count])

这样每次渲染,都会更新useEffect函数,拿到最新的count值。

  1. useRef存储变量
const [count, setCount] = useState(0);
const latestCount = useRef();
latestCount.current = count;
useEffect(()=>{
	const timeId = setInterval(()=>{
		console.log(latestCount.current)
	}, 1000);
	return () => clearInterval(timeId);
}, []);

导致闭包陷阱的原因

  1. 异步函数
  2. window.addEventListener绑定事件