React 的闭包陷阱 + 状态异步更新机制

🔹1. 为什么 useState 更新了,但打印是旧值?

scss 复制代码
const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  console.log("count:", count); // ❌ 打印的还是旧值
};

原因:

  • setCount 并不会立刻修改 count,而是 调度一次重新渲染
  • 在当前函数调用上下文里,count 还是旧的。
  • 下一次渲染函数执行时,count 才会变成新值。

👉 React 的 state 更新是异步的、批量的


🔹2. 为什么 useEffect 里总是打印上一次的值?

scss 复制代码
useEffect(() => {
  console.log("count in effect:", count);
}, [count]);

这个逻辑其实是正确的

  • useEffect 执行时机是 DOM 更新后
  • 打印的值就是本次 render 的 count,但因为 console.log 常和点击事件混用,很多人会以为"怎么总是落后一步"。

示例:

rust 复制代码
// 初始 count=0
点击按钮 -> setCount(1)
-> render(count=1)
-> DOM 更新
-> useEffect 执行,打印 1 ✅

如果你在 点击回调里打印effect 里打印对比,就会发现一个"延迟一拍"的错觉。


🔹3. 怎么解决/避免?

✅ 方法1:用 函数式更新 拿到最新值

ini 复制代码
setCount(prev => {
  console.log("最新 count:", prev + 1);
  return prev + 1;
});

这样不会受闭包影响,永远基于最新状态更新。


✅ 方法2:在 useEffect 里观察变化

scss 复制代码
useEffect(() => {
  console.log("count 更新:", count);
}, [count]);

更符合 React 思路:状态变化 → 副作用


✅ 方法3:如果确实要获取"最新的值",用 useRef

ini 复制代码
const countRef = useRef(count);

useEffect(() => {
  countRef.current = count; // 同步最新值
}, [count]);

// 在任何地方访问 countRef.current 都是最新的

🔹4. 总结口诀

  1. setState 不会立即更新,打印的还是旧值
  2. useEffect 打印的其实是对的值,只是它本来就滞后执行
  3. 想要拿到最新值 → 用函数式更新或 useEffect/useRef
相关推荐
鱼樱前端13 分钟前
uni-app快速入门章法(一)
前端·uni-app
zhangxuyu111833 分钟前
flex布局学习记录
前端·css·学习
掘金一周40 分钟前
🍏让前端去做 iPhone 的液态玻璃❓ | 掘金一周 10.2
前端·人工智能·后端
Keepreal4961 小时前
谈谈对javascript原型链的理解以及原型链的作用
前端·javascript
itslife1 小时前
vite 源码 - 配置
前端·javascript
Keepreal4961 小时前
Typescript中type和interface的区别
前端·typescript
RJiazhen1 小时前
从迁移至 Rsbuild 说起,前端为什么要工程化
前端·架构·前端工程化
小红1 小时前
网络通信核心协议详解:从ARP到TCP三次握手与四次挥手
前端·神经网络
影子信息2 小时前
uniapp 日历组件 uni-datetime-picker
前端·uni-app