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
相关推荐
IT_陈寒15 分钟前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x31 分钟前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者1 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
袋鱼不重2 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
Fireworks2 小时前
深入vue3源码解读 -- 1、响应式的基础概念
前端
程序员黑豆2 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程
hunterandroid2 小时前
文件存储:内部存储与外部存储
前端
NorBugs3 小时前
飞机大战 Low 版 (Made in AI)
前端
angerdream3 小时前
Android手把手编写儿童手机远程监控App之agentweb如何实现全屏
前端
星栈4 小时前
10 分钟跑起第一个 Dioxus 应用:`dx` CLI、`rsx!` 和热更新好不好用
前端·rust·前端框架