什么是闭包陷阱
了解闭包陷阱之前,我们要先知道函数式组件是怎么渲染的。
所谓的闭包陷阱,就是在函数式组件中,我们拿不到通过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。
解决方案
- 在依赖数组中加入count
useEffect(()=>{
const timeId = setInterval(()=>{
console.log(count);
},1000)
return ()=>{clearInterval(timeId)}
},[count])
这样每次渲染,都会更新useEffect函数,拿到最新的count值。
- useRef存储变量
const [count, setCount] = useState(0);
const latestCount = useRef();
latestCount.current = count;
useEffect(()=>{
const timeId = setInterval(()=>{
console.log(latestCount.current)
}, 1000);
return () => clearInterval(timeId);
}, []);
导致闭包陷阱的原因
- 异步函数
window.addEventListener绑定事件