为什么 React 18 的 concurrent 模式没人敢开?真不是我怂,是它太怪

首先说下,我是真的试过开 concurrent 模式。

不是云试,是线上的业务真上过。然后被劝退了,半夜 2 点 rollback,连个背锅侠都没找着。

你问为啥没人敢用?不是大家不学,是你学了也用不上。甚至还会反噬你原来写得好好的代码。


用了个寂寞:自动 batching 把逻辑搞乱了

React 18 一开 concurrent,自动 batching 就默认生效了。

原来你习惯:

js 复制代码
setA(1);
setB(2);

就算是两个状态,它是同步的,你知道它啥时候变,effect 会跑几次你也能心里有数。

现在不是了,全给你 batch 一起,连一些 fetch 回来的回调里也一起 batch,你代码顺序对了,副作用顺序不一定对了 ,然后你就开始在控制台打 console.log(123) 找状态是在哪一步跑飞的......

调试体验直线下坠,尤其你用了 useEffectuseLayoutEffectuseRef 这些混合控制流程的钩子之后,整个状态像走迷宫。

调试日志:看得懂算你赢

下面是一段我调 concurrent 的时候打的调试日志,建议配合 ctrl+f 灵魂搜索状态变化顺序服用

js 复制代码
useEffect(() => {
  console.log('[Effect] A', flag); // 本来想监听 flag
}, [flag]);

useEffect(() => {
  console.log('[Effect] B', count); // 想看 count
}, [count]);

const handleClick = () => {
  console.log('---click---');
  setCount(count + 1);
  setFlag(!flag);
  console.log('state updated');
};

点击一次按钮,期望输出:

js 复制代码
    ---click---
    state updated
    [Effect] A true
    [Effect] B 2

结果实际输出是:

js 复制代码
    ---click---
    state updated
    [Effect] B 2
    [Effect] A true

我:???

再点第二次:

js 复制代码
    ---click---
    state updated
    [Effect] A false

???

第二次 B 的 effect 根本没跑。

而且有时候 console.log 甚至不按顺序打印了。你知道那种感觉吗?调 bug 的时候最怕的就是连 console 都不可信。

最玄学的是,加了一行 console.log('---split---') 整个顺序又变了,说明 batching 和调度时机是动态计算的,不是你想象的同步 + predictable。

调着调着我开始怀疑人生,感觉不是我在控制代码,是 React 在控制我。

表面上很高级,其实就离谱

startTransition() 你看起来像是"优化体验"的神技。

js 复制代码
startTransition(() => {
  setList(bigData);
});

说白了就是"这个操作可以慢点,用户别着急"。

但你别忘了国内的产品经理喜欢啥?------一点击就响应,一搜索就变,一输入就提示。

然后你用了 startTransition(),结果点击按钮 1 秒之后列表才更新,PM 直接甩脸子说:"这是不是你接口没调通?"

你没错,React 也没错,但用户体验感知错了。

这种"慢是故意的"体验,不是每个业务场景都能接受的。你在工具型产品能用,用在直播电商场景试试看......


官方说是可选,但其实你一用 createRoot 就进坑了

React 18 升级后,文档一直说:"你要用 concurrent 要用 createRoot 哦,legacyRoot 就是以前的模式。"

好啊,我听话,用了:

js 复制代码
const root = createRoot(document.getElementById('root'));

然后一堆"意想不到的行为"就来了。老项目你只要引了某些第三方库,比如 MobX、Zustand、Formily 这些带点"响应式"特性的,有可能你都不知道它在什么时候订阅了状态,反应已经不是你能控制的了

最搞的是,有些组件突然"变聪明"了,render 时机自己决定了,连 useEffect 都可能晚点触发......

就像你本来以为你开了自动挡,结果发现方向盘也会自己打。


那些说 concurrent 好用的人,有几个是线上跑业务的?

GitHub 上很多项目是用了 concurrent 的,甚至 React 18 刚出的时候你去掘金搜一圈,全是"如何开启 concurrent mode 提升性能"的文章。

但你看看他们项目有几个是线上复杂业务?

要么是组件库,要么是 demo,要么是静态展示页。

真跑起来的中后台系统,有表格、有筛选、有嵌套 modals、有异步 loading 状态的那种,很少有人敢真的一把梭 concurrent。

不是说不能用,但它的坑不是你测试阶段能测出来的。

有些坑,只有用户点得飞快的时候,或者你状态切得特别多的时候,它才炸出来。


再说句真心话:你现在不用,反而是对团队负责

我见过有些小团队,前端负责人看到 React 18 出了新特性,就要大家统一升级,还要用上 concurrent,说"这叫拥抱未来"。

结果版本升了,性能没提升多少,bug 数量翻了三倍。然后他跑去说"React 18 还不太稳定",把锅甩给框架。

技术选型不是看 hype 的,是看团队能不能 hold 得住。

你搞了 concurrent,调试体验下来了,状态不可预测,组件行为飘忽不定,就算性能真提升了 100ms,没人 care,用户还是说你卡。


那到底什么时候能用?

讲真,这东西不是废的,但它更像是为未来设计的。

你在做类似 Instagram、Notion、Figma 这种"实时、复杂、多操作流"前端产品时,它是有意义的,能把复杂的渲染任务拆开,保 UI 流畅。

但如果你现在的页面是普通 CRUD 表格、筛选、增删改查,用 concurrent 纯属给自己找不痛快。


Concurrent 不是不香,是你得能驾驭它🤯

说到底,不是 concurrent 模式不行,而是它不适合所有人现在立刻用上

你要有时间改代码结构、重构副作用逻辑、打通调试链路、甚至调教状态库,那你可以用。

但要是你项目还处于"能跑就行"、测试流程都不完善的阶段,老老实实用同步模式,至少心里有数,出了问题也好查。

React 给了我们选择,但别急着选择你还没准备好驾驭的东西。

相关推荐
IT_陈寒20 分钟前
React状态管理终极对决:Redux vs Context API谁更胜一筹?
前端·人工智能·后端
gxp1231 小时前
初学React:请求数据参数未更新 && 数据异步状态更新问题
react.js
Kagol1 小时前
TinyVue 支持 Skills 啦!现在你可以让 AI 使用 TinyVue 组件搭建项目
前端·agent·ai编程
柳杉1 小时前
从零打造 AI 全球趋势监测大屏
前端·javascript·aigc
simple_lau1 小时前
Cursor配置MasterGo MCP:一键读取设计稿生成高还原度前端代码
前端·javascript·vue.js
睡不着先生1 小时前
如何设计一个真正可扩展的表单生成器?
前端·javascript·vue.js
天蓝色的鱼鱼2 小时前
模块化与组件化:90%的前端开发者都没搞懂的本质区别
前端·架构·代码规范
明君879972 小时前
Flutter 如何给图片添加多行文字水印
前端·flutter
进击的尘埃2 小时前
AI 代码审查工具链搭建:用 AST 解析 + LLM 实现自动化 Code Review 的前端工程方案
javascript
juejin_cn2 小时前
[转][译] 从零开始构建 OpenClaw — 第五部分(对话压缩)
javascript