下面是一个简单的函数组件,有两个按钮:“alert”、“add”。
如果先点击“alert”按钮,再点击一次“add”按钮,那么弹窗框中的值和页面中展示value
分别是什么?
1const FunctionComponent = () => { 2 const [value, setValue] = useState(1) 3 4 const log = () => { 5 setTimeout(() => { 6 alert(value) 7 }, 3000); 8 } 9 10 return ( 11 <div> 12 <p>FunctionComponent</p> 13 <div>value: {value}</div> 14 <button onClick={log}>alert</button> 15 <button onClick={() => setValue(value + 1)}>add</button> 16 </div> 17 ) 18}
参考答案:
弹出的值是 1,页面显示的值是 2
我们发现弹出的值和当前页面显示的值不相同。
换句话说:log 方法内的 value 和点击动作触发那一刻的 value 相同,value 的后续变化不会对 log 方法内的 value 造成影响。
这种现象被称为“闭包陷阱”或者被叫做“Capture Value” :函数式组件每次render 都会生产一个新的 log 函数,这个新的 log 函数会产生一个在当前这个阶段 value 值的闭包。
上面例子 “闭包陷阱” 的分析:
如何让弹窗中展示最新的value值呢?
1const FunctionComponent = () => { 2 const [value, setValue] = useState(1) 3 const countRef = useRef(value) 4 5 const log = () => { 6 setTimeout(() => { 7 alert(countRef.current) 8 }, 3000); 9 } 10 11 useEffect(() => { 12 countRef.current = value 13 }, [value]) 14 15 return ( 16 <div> 17 <p>FunctionComponent</p> 18 <div>value: {value}</div> 19 <button onClick={log}>alert</button> 20 <button onClick={() => setValue(value + 1)}>add</button> 21 </div> 22 ) 23}
useRef 每次 render 时都会返回同一个引用类型的对象,我们设置值和读取值都在这个对象上处理,这样就能获取到最新的 value 值了。
最近更新时间:2024-07-23