首先说下,我是真的试过开 concurrent 模式。
不是云试,是线上的业务真上过。然后被劝退了,半夜 2 点 rollback,连个背锅侠都没找着。
你问为啥没人敢用?不是大家不学,是你学了也用不上。甚至还会反噬你原来写得好好的代码。
用了个寂寞:自动 batching 把逻辑搞乱了
React 18 一开 concurrent,自动 batching 就默认生效了。
原来你习惯:
js
setA(1);
setB(2);
就算是两个状态,它是同步的,你知道它啥时候变,effect 会跑几次你也能心里有数。
现在不是了,全给你 batch 一起,连一些 fetch
回来的回调里也一起 batch,你代码顺序对了,副作用顺序不一定对了 ,然后你就开始在控制台打 console.log(123)
找状态是在哪一步跑飞的......
调试体验直线下坠,尤其你用了 useEffect
、useLayoutEffect
、useRef
这些混合控制流程的钩子之后,整个状态像走迷宫。
调试日志:看得懂算你赢
下面是一段我调 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 给了我们选择,但别急着选择你还没准备好驾驭的东西。