为什么 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 给了我们选择,但别急着选择你还没准备好驾驭的东西。

相关推荐
AAA阿giao3 分钟前
qoder-cli:下一代命令行 AI 编程代理——全面解析与深度实践指南
开发语言·前端·人工智能·ai编程·mcp·context7·qoder-cli
我有一棵树6 分钟前
Vite 7 中 dev 没样式、build 却正常:一次由 CSS import 位置引发的工程化问题
前端·javascript·vue.js
@Autowire7 分钟前
CSS 中 px、%、vh、vw 这四种常用单位的区别
前端·css
怕浪猫8 分钟前
React从入门到出门第七章 管理你的CSS 模块化样式控制方案
javascript·css·react.js
@Autowire10 分钟前
CSS 中「继承属性」的核心知识,包括哪些属性可继承、继承的规则、如何控制继承(继承/取消继承)
前端·css
万行16 分钟前
机器人系统ros2&期末速通2
前端·人工智能·python·算法·机器学习
天天向上102416 分钟前
css Grid常用布局
前端·css
lili-felicity20 分钟前
React Native for Harmony:地址管理页面(新增+编辑)完整实现
react native·react.js·harmonyos
syty202021 分钟前
RedisTemplate方法汇总
前端·bootstrap·html