function createIncrement(incBy) {
let value = 0;
function increment() {
value += incBy;
console.log(value);
}
const message = `Current value is ${value}`; function log() { console.log(message); }
return [increment, log];
}
const [increment, log] = createIncrement(1);
increment(); // 1
increment(); // 2
increment(); // 3
// 不能正确工作!
log(); // "Current value is 0"
[increment, log] = createIncrement(1)返回一个函数元组:一个函数增加内部值,另一个函数记录当前值。然后,increment()的3次调用将 value递增到3。最后,log()调用打印消息是 Current value is 0,这有点出乎意料的,因为此时 value 为 3 了。 ) N: C) S. {9 T/ A7 M& \ log()是一个过时的闭包。闭包 log()捕获了值为 "Current value is 0"的 message 变量。即使 value 变量在调用increment()时被增加多次,message变量也不会更新,并且总是保持一个过时的值 "Current value is 0"。过时的闭包捕获具有过时值的变量。 + V) T$ I+ `5 v2.修复过时的闭包! i0 k1 X7 |3 |" H
修复过时的log()问题需要关闭实际更改的变量:value的闭包。我们将语句 const message = ...; 移动到 log() 函数内部: 5 U, R/ `( D# F3 r4 K f# e) Q
正确设置依赖项后,一旦count发生变化,useEffect()就会更新闭包。 # T* w6 [+ n8 h0 G3.2 useState(): i9 z+ Q# m. M- H/ A' g. x
<DelayedCount>组件有1个button ,以1秒延迟异步增加计数器: . c& ?- I- z* ~7 c9 U W
这就是为什么在状态更新过程中出现的过时装饰问题可以通过函数这种方式来解决。% P4 E6 u7 U" h 4.总结: {: J& C8 _! x6 l; H
当闭包捕获过时的变量时,就会发生过时的闭包问题。解决过时闭包的有效方法是正确设置React钩子的依赖项。或者,在失效状态的情况下,使用函数方式更新状态。 / V: D( D) \5 b. l) F1 y ! N7 Z V- T5 Y( x) L