感觉第一张和第二张没什么区别。但第一个代码片段可以解决陈旧的闭包问题。那么,为什么第二个不能呢?我实在想不通。谁能从JavaScript闭包的原理来解释一下吗?
// ========================== First code snippet ========================
let _formVal
export default function App() {
const [formVal, setFormVal] = useState('');
_formVal = formVal
const handleSubmit = useCallback(() => {
console.log('_formVal:', _formVal);
}, []);
return (
<>
<input
onChange={(e) => {
setFormVal(e.target.value);
}}
value={formVal}
/>
<MemoziedSuperHeavyComponnent onSubmit={handleSubmit} />
</>
);
}
// ========================== Second code snippet ========================
export default function App() {
const [formVal, setFormVal] = useState('');
const _formVal = formVal
const handleSubmit = useCallback(() => {
console.log('_formVal:', _formVal);
}, []);
return (
<>
<input
onChange={(e) => {
setFormVal(e.target.value);
}}
value={formVal}
/>
<MemoziedSuperHeavyComponnent onSubmit={handleSubmit} />
</>
);
}
在第一个示例中,仅创建了一个
_formVal
变量,该变量位于顶部模块范围级别,因此这就是函数组件读取和更新的变量。
在第二个示例中,为组件的每个渲染创建多个
_formVal
变量,因为每次重新渲染都会再次调用您的 App
函数。由于您的 useCallback()
引用永远不会更新,并且始终是在初始渲染时创建的第一个函数(由于空依赖项 []
),因此该函数将始终可以访问创建的第一个 _formVal
变量,而不是后续的变量未来的渲染。