- 作者:老汪软件技巧
- 发表时间:2024-09-14 15:02
- 浏览量:
pnpm create vite react-closure-test --template react-ts
2 修改 index.tsx
3 示例组件
下面是一个通过定时器不断累加 count 的组件:
4 问题分析
大家可能会认为 count 会每秒加 1,但实际上不会。
原因是 setCount 时拿到的 count 一直是 0。
这是因为 useEffect 的依赖数组是空的 [],即只会执行并保留第一次的函数,而第一次的函数引用了当时的 count,形成了闭包。
5 解决方法5.1 方法一:使用 setState 的函数参数
可以通过 setState 的函数参数来解决闭包问题:
运行结果:
5.2 方法二:使用 useReducer
使用 useReducer 也可以解决闭包问题,因为它是通过 dispatch 一个 action,不直接引用 state:
5.3 方法三:使用 useEffect 的依赖数组
在某些情况下,必须使用 state,这时可以利用 useEffect 的依赖数组:
这种方法虽然能解决闭包陷阱,但在定时器的场景中并不合适,因为每次 count 变化都会重新启动定时器。
5.4 方法四:使用 useRef
可以使用 useRef 来解决定时器的闭包问题:
通过 useRef 创建 ref 对象,保存执行的函数,每次渲染更新 ref.current 的值为最新函数。
这样,定时器执行的函数里就始终引用的是最新的 count。
6 自定义 Hook
我们可以将定时器的处理封装成一个自定义 Hook:
使用 useCallback 包裹返回的函数,可以避免该参数的变化,配合 memo 可以减少不必要的渲染。
通过以上方法,我们可以有效地解决 React 中的闭包陷阱问题。