导读:本期聚焦于罗经纬创作的《龙虾之父一条推文,Loop 时代终结?聊聊 Immer 作者为何放弃 React Hook 状态管理》,敬请观看详情。Immer 的作者 Michel Weststrate 最近在社交媒体上的一条推文引发了前端圈的广泛讨论,他直言自己已经不再推荐在 React Hook 中使用 Immer 的生产集成方案,甚至建议大家重新审视现有的状态管理模式。作为被无数 React 项目依赖的不可变数据工具,Immer 与 useImmer 这类 Hook 方案曾经被视为简化状态更新的最佳实践。这条推文背后到底传递了什么信号?React 官方的状态管理思路发生了哪些变化?useSyncExternalStore 与不可变更新之间的取舍又该如何理解?本文将从 Immer 的工作原理讲起,分析它在 Hook 时代遇到的真实瓶颈,探讨新的状态管理范式,帮助你在下一个项目中做出更合适的技术选型。

被称为“龙虾之父”的 Michel Weststrate 是 Immer 和 MobX 的作者,他在前端社区的影响力毋庸置疑。Immer 自发布以来,几乎成了 React 项目中处理不可变数据更新的标配工具,配合 useImmer 和 useImmerReducer 这两个 Hook,开发者可以用可变的写法实现不可变的数据更新,大幅降低了手写展开运算符的心智负担。然而就是这样一位把 Immer 推向巅峰的人,却公开表示自己在 Hook 中使用 Immer 的方式已经不再是首选方案,这条推文一出,社区里关于“Hook 状态管理是否走错了方向”的讨论瞬间被点燃。

龙虾之父一条推文,Loop 时代终结?聊聊 Immer 作者为何放弃 React Hook 状态管理

先搞清楚 Immer 到底解决了什么问题

React 的核心机制是基于引用相等性来判断数据是否变化,从而决定组件是否需要重新渲染。这就要求所有状态更新都必须产生新的引用,而不能直接修改原对象。在没有 Immer 的年代,开发者只能通过层层展开运算符来复制嵌套对象,代码既冗长又容易出错。比如要更新一个深层嵌套的列表项属性,往往需要写出三四层展开的代码,稍有疏忽就会意外修改了原始数据。

Immer 的思路是利用 Proxy 拦截所有的写操作,把你对草稿对象的修改记录下来,最后基于这些修改生成一颗新的不可变树。这样你就可以写出看似可变的代码,Immer 会在背后帮你完成结构共享的拷贝。这种方式确实优雅,也正因为如此,useImmer 在 Hook 时代迅速流行开来。

import { useImmer } from 'use-immer';

function TodoList() {
  const [todos, updateTodos] = useImmer([]);
  
  const toggleDone = (id) => {
    updateTodos((draft) => {
      const item = draft.find((t) => t.id === id);
      if (item) item.done = !item.done;
    });
  };
  
  return <ul>{todos.map((t) => <li key={t.id}>{t.text}</li>)}</ul>;
}

这段代码看起来非常自然,但在这种自然背后,隐藏着一些容易被忽视的成本。Proxy 拦截是有运行时开销的,对于高频更新的大对象树,这个开销会被放大。同时,草稿对象的行为在某些边界情况下与普通对象并不完全一致,例如在草稿上调用某些原生方法或者将草稿对象传出更新函数,都可能触发难以排查的问题。

Michel Weststrate 那条推文真正想说什么

如果只看推文表面,很容易误读为“Immer 被废弃了”,但实际上作者表达的核心观点是:在 Hook 时代,把状态管理的复杂度全部压在组件内部的 useState 系列方案上,本身就是一个值得反思的架构选择。他多次强调,Immer 作为底层库依然健康,问题在于开发者把它和 Hook 深度绑定后形成的那套使用范式。

具体来说,当一个应用的状态全部通过 useImmer 散落在各个组件里时,状态的归属变得模糊,组件的重渲染范围难以控制,跨组件的状态同步也需要借助 Context,而 Context 的粗粒度更新会让性能问题雪上加霜。作者本人更倾向于把状态收敛到外部 store 中,组件通过订阅的方式来消费状态,这样状态的变更边界清晰,也更容易做性能调优。

React 官方后来提供的 useSyncExternalStore 这个 Hook 其实印证了这一方向。它为外部 store 与 React 的并发渲染之间提供了标准化的桥接方式,保证了在撕裂场景下的一致性。也就是说,React 社区的主流思路正在从“状态放进组件”转向“状态放到外部,组件只做订阅与渲染”。

不可变更新还有必要吗,新的实践建议

即便转向外部 store,不可变性本身依然重要,它是 React 渲染优化的基石。Immer 在纯数据层的使用依然有价值,比如在 Zustand、Redux Toolkit 的 reducer 中,produce 依然是简化深层更新的利器。变化的只是 Immer 的使用位置:从组件内的 Hook 层面,退回到状态库的更新函数层面。

import { create } from 'zustand';
import { produce } from 'immer';

const useStore = create((set) => ({
  user: { profile: { name: '', tags: [] } },
  updateName: (name) =>
    set((state) =>
      produce(state, (draft) => {
        draft.user.profile.name = name;
      })
    ),
}));

// 组件只负责订阅,粒度可以精确到单个字段
function NameDisplay() {
  const name = useStore((s) => s.user.profile.name);
  return <span>{name}</span>;
}

这种模式把 Proxy 的开销限制在真正发生更新的那一刻,组件订阅的是具体的字段切片,只有被订阅的数据变化时才会重渲染。相比把整个草稿对象塞进 Context,性能表现和可维护性都有明显提升。

对于新项目,可以参考这样几条原则:第一,局部 UI 状态继续用 useState,简单直接;第二,跨组件共享的领域状态交给外部 store,并用 selector 控制订阅粒度;第三,深层不可变更新统一在 store 的更新逻辑里用 produce 处理,不在组件里直接操作草稿;第四,如果一个对象树特别庞大且更新极其频繁,可以评估放弃 Proxy 方案,改用细粒度的原子化状态库,避免为不需要更新的部分付出代理成本。

龙虾之父的一条推文并非宣判某个工具的死刑,而是提醒大家不要把任何一种模式当作永恒的最佳实践。技术选型永远要回到具体场景:状态复杂度、团队熟悉度、性能敏感度,这三者共同决定了哪条路更适合你。理解了 Immer 的原理边界与 Hook 状态管理的演进逻辑,你就能在下一轮范式变化到来时,比社区跑得更快一步。

ImmerReact Hook状态管理修改时间:2026-09-06 03:02:32

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260906/51297.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。