vault backup: 2026-04-30 11:24:07
This commit is contained in:
@@ -78,6 +78,20 @@ const [state, setState] = useState<T>(initialValue);
|
||||
const [items, setItems] = useState(() => loadFromStorage()); // 仅首次渲染执行
|
||||
```
|
||||
|
||||
### 闭包陷阱(Closure Trap)
|
||||
|
||||
> [!warning] 高频踩坑点:React 每次渲染都创建全新的作用域和变量副本
|
||||
|
||||
```tsx
|
||||
const [count, setCount] = useState(0);
|
||||
setTimeout(() => setCount(count + 1), 1000); // ❌ count 始终为首次渲染时的快照值
|
||||
```
|
||||
|
||||
**为什么?** React 的 `setCount` 不是异步函数,而是 **闭包捕获了渲染时的变量快照** —— 第一次渲染后,`handleClick` 里的 `count` 就被锁死在 `0` 上了。
|
||||
|
||||
> [!tip] 如何修复?
|
||||
> 有两种思路:让 React 自己提供最新状态(updater),或者用 ref 持有一个始终更新的引用。具体方案与对比见 → [[05-核心 Hooks/01-闭包陷阱|详解]]
|
||||
|
||||
### 关键行为
|
||||
|
||||
> [!tip] 核心认知
|
||||
@@ -89,22 +103,6 @@ const [items, setItems] = useState(() => loadFromStorage()); // 仅首次渲染
|
||||
| 连续多次 setState | React 18 自动合并为一次 re-render |
|
||||
| 在非 React 代码中调用 | 使用 `startTransition` / `flushSync` 控制 |
|
||||
|
||||
```tsx
|
||||
function BadCounter() {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
// ❌ 闭包陷阱:count 始终捕获定义时的 0
|
||||
setTimeout(() => setCount(count + 1), 1000);
|
||||
}
|
||||
|
||||
function GoodCounter() {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
// ✅ 使用 updater 函数,获取最新值
|
||||
setTimeout(() => setCount(c => c + 1), 1000);
|
||||
}
|
||||
```
|
||||
|
||||
### 不可变更新模式
|
||||
|
||||
```tsx
|
||||
|
||||
Reference in New Issue
Block a user