什么是闭包陷阱?
在React的uesEffect中使用定时器,在定时器中对state进行操作,但是在useEffect的第二个参数中没有加入使用的state,就会形成闭包陷阱。 解释:从“闭包陷阱”这个词就能知道其中含义,在使用闭包的情况下,和我们预期的结果不太一样,就像一个陷阱。
闭包陷阱的案例
import React, {useEffect, useState} from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count + 1);
}, 5000)
setInterval(() => {
console.log(count)
}, 5000)
}, [])
return (<>
</>
);
}
如果我们想要的结果是每隔5秒,打印的情况是 0 ,1,2,3,... 但是实际的情况是 0,0,0,0,....
原因
在useEffect的defs是[]的时候,钩子里面的callBack函数只执行一次,每一个钩子都有自己的上下文,这个时候虽然通过useInterval改变了state,但是钩子里面的上下文中的state并没有改变,一直使用的是第一次的state,所以就出现这种情况。
解决方案
defs的依赖添加
count每次改变,因为useEffect添加了依赖,所以useEffect的中引用的count也会改变,需要注意的是每次在创建定时器前,先要清理之前的定时器
import React, {useEffect, useState} from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer1 = setInterval(() => {
setCount(count + 1);
}, 5000)
const timer2 = setInterval(() => {
console.log(count)
}, 5000)
return () => {
window.clearInterval(timer1)
window.clearInterval(timer2)
}
}, [count])
return (<>
</>);
}
使用useRef
useRef的特别之处是可以记录多次渲染的状态,或者说useRef只会在初次渲染的时候被创建
import React, {useEffect,useRef} from "react";
export default function App() {
const ref = useRef(0)
useEffect(() => {
const timer1 = setInterval(() => {
ref.current +=1;
console.log(ref.current)
}, 5000)
}, [])
return (<>
</>);
}