闭包指的是那些引用了另一个函数作用域中变量的函数
function createIncrement() {
let value = 0;
return function increment() {
console.log(++value);
}
}
// 1.创建函数
let inc = createIncrement();
// 2.调用
inc(); // 1
inc(); // 2
// 3.销毁, 设置为null会解除对函数的引用,从而让垃圾回收程序释放掉内存
inc = null
React Hooks闭包问题
useEffect注册时,会将所有已定义变量获取一遍,当做状态值。获取的second值是0,所以匿名箭头函数能访问到的状态second值为0,所以如果执行setSecond(second+1)用的second一直是状态值0,而不是最新的second。
const [second, setSecond] = useState(0);
useEffect(() => {
let timer = setInterval(() => {
// 这时候的second由于闭包的原因,一直是0,所以只能看到second变化一次。
setSecond(second+1);
}, 1000)
}, [])
// 模拟实现
// function effect(){
// return (fun:Function) => {
// fun(...arguments)
// }
// }
// const useEffect = effect({second:0})
// useEffect(({second})=>{
// for (let i = 0; i<5; i++){
// const num = second + 1
// console.log('改正前',num)
// } // 1 1 1 1 1
// let num = second
// for (let i = 0; i<5; i++){
// ++num
// console.log('改正后',num)
// } // 1 2 3 4 5
// })
解决方案1:
重新定义一个状态值,改变这个状态值
const [second, setSecond] = useState(0);
useEffect(() => {
let num = second
let timer = setInterval(() => {
num+=1 //不能直接second+=1,因为second没法直接更改值
setSecond(num);
}, 1000)
}, [])
解决方案2:
setXxx接收的如果是个函数,会自动将最新的state当做函数参数。
const [second, setSecond] = useState(0);
useEffect(() => {
let timer = setInterval(() => {
// n 也就是最新的second值
setSecond(n => {return n + 1});
}, 1000)
}, [])