Closures and React
JavaScript闭包概念
React闭包应用useEffectEvent
Understanding Closures in JavaScript
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives a function access to its outer scope. In JavaScript, closures are created every time a function is created, at function creation time.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
简单来说,闭包就是指一个函数能够“记住”并访问它的词法作用域(也叫环境或上下文),即使这个函数是在它原始定义的作用域之外执行。
核心特性:
- 闭包可以保存外部函数作用域中的变量,即使外部函数已经返回。
- 这些变量不会被销毁,因为闭包持有了对它们的引用。
1 | function outer() { |
闭包的底层实现
作用域链(Scope Chain):
- 每个函数在创建时,会附带它的词法作用域(外部函数的变量环境)。
- 闭包通过作用域链,逐层查找变量。
变量存储和垃圾回收:
- 局部变量通常存储在栈中,当函数执行完毕会被销毁。
- 如果闭包引用了这些变量,它们会被移到堆内存中,直到闭包被销毁才会被回收。
Applying Closures in React
React渲染机制与闭包
每次渲染创建一个闭包。
每次渲染的 snapshot 是独立的,与其他渲染互不干扰。
React 的函数式组件在每次渲染时:
- 会执行整个函数组件。
- 捕获当前渲染时的 state 和 props。
- 对于函数组件内部定义的所有函数(包括 event handler 和
useEffect
中的回调),这些函数都会捕获当前渲染时的 state 和 props。
useEffect的执行与闭包
每次执行 useEffect
时:
- React 会捕获当前渲染时的 state 和 props。
- 如果
useEffect
的依赖数组中有变化,React 会重新执行这个 useEffect。 useEffect
内部定义的函数会捕获当前渲染时的 state 值。
重新理解React的一些语法/规则
闭包陷阱 Closure Trap
在 JavaScript 中使用闭包时,由于闭包捕获了当前作用域中的变量或状态的“快照”,而不是随时访问变量的最新值,导致程序行为与预期不符的一种情况。
1 | function Counter() { |
useState
: set functions
setState((prevState) => prevState + 1)
https://react.dev/reference/react/useState#setstate
函数式更新确保状态更新逻辑基于最新的状态,而不是捕获的旧值。
1 | const handleClick = () => { |
useEffect
: Dependency Array
https://react.dev/reference/react/useEffect#specifying-reactive-dependencies
在 useEffect
的依赖数组中明确列出所有依赖项,确保闭包始终访问最新的状态或变量。
1 | useEffect(() => { |
useEffectEvent
https://react.dev/reference/react/experimental_useEffectEvent
1 | function Counter() { |
在 useEffect
中定义普通函数和使用 useEffectEvent
的区别?
普通函数 + useEffect
- 函数引用不稳定,每次渲染都会重新创建
- 可能访问到旧的 state 和 props(需要显式管理依赖数组,否则就可能因为陷入其他闭包取到旧的值)
useEffectEvent
- 自动获取最新状态,无需手动管理依赖
useEffectEvent
代替案
useRef
to maintain stable references that persist across rendersuseCallback
to memoize functions, ensuring they have stable references