闭包指的是那些引用了另一个函数作用域中变量的函数
function createIncrement() {let value = 0;return function increment() {console.log(++value);}}// 1.创建函数let inc = createIncrement();// 2.调用inc(); // 1inc(); // 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 = secondlet 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)}, [])
