vault backup: 2026-04-30 11:24:07

This commit is contained in:
2026-04-30 11:24:07 +08:00
parent b8ed6c2e3f
commit f8c6afa9bd
2 changed files with 93 additions and 16 deletions
+14 -16
View File
@@ -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