You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React直接修改state后触发强制重渲染为何存在问题

核心结论先放前面

你这套写法在当前你写的这个极简测试用例下确实能正常工作——毕竟setUpdateRequired({})每次都会生成新的对象引用,100%会触发组件重渲染,重渲染时从clicks.value读到的就地修改后的值自然会正确显示在页面上。
但这种写法的问题从来不是“当前场景跑不起来”,而是它完全踩中了React运行机制的所有暗坑,会在你完全没预料到的场景下产生极难排查的bug,具体问题全部都是可复现的实锤,不是空泛的“最佳实践要求”:

1. 你以为成立的三个前提,根本挡不住React自身的运行逻辑

你提出的三个“可行”前提:数据不跨组件共享、单函数持有修改权限、修改时组件不读值——这些假设在React的调度规则面前根本不成立:

  • 首先,React默认会对做了引用相等比较的渲染逻辑做跳过重渲染优化。哪天你给这个Counter组件包一层React.memo,或者把clicks对象传给任意子组件,因为你从来没给clicks换过引用,子组件的props浅比较永远会判断“值没变化”,根本不会同步你就地修改的内容。举个实跑的例子:你加一行<ShowClicks count={clicks} />,哪怕你点了10次按钮把值改到-10,这个子组件因为props引用没变,永远只会显示初始的0。
  • 其次,React 18的自动批处理、可中断渲染机制,根本不会给你“修改时组件不读值”的保证。如果一次渲染被更高优先级的更新打断、直接丢弃,你就地修改的clicks.value是挂在对象上的全局可变值,根本跟不上React的渲染回滚逻辑走。比如第一次渲染到一半被打断,已经把clicks.value改成了10,React扔掉这次渲染结果准备重跑的时候,读到的clicks.value已经是10,根本不是你初始的0,这时候渲染出来的页面和你逻辑上预期的状态完全对不上,还不会报任何错。
  • 还有最隐蔽的异步场景:如果你在setTimeout、接口回调、事件回调里修改clicks.value,但是中间忘了调用setUpdateRequired({}),React根本不知道你改了数据,页面上的显示值就是错的。比如你在一个异步请求成功的回调里把clicks.value改成100,忘了触发重渲染,用户看到的永远是旧值。

2. 你以为省了复制的性能开销,实际上反而会带来更严重的性能损耗

你当初抵触不可变更新的核心原因是“大规模数组复制开销大、拷贝逻辑复杂”,但你这套写法下:

  • 所有React内置的渲染优化手段(React.memo、useMemo、useCallback)会完全失效。因为这些优化的核心判断逻辑就是“比较引用是否变化”,而你永远不换clicks的引用,任何依赖clicks的派生值、任何依赖clicks的子组件,都无法通过引用判断数据是否真的更新,到最后你只能硬触发全量重渲染,性能反而比老老实实做不可变更新差得多。
  • 举个实场景的例子:你在state里存一个10万行的列表,你就地修改了其中某一行的内容。按照官方的不可变更新逻辑,你可以通过引用比较,只让依赖这一行的子组件重渲染,其他99999行对应的组件完全可以跳过更新。但你这套写法下,列表引用永远不变,子组件根本不知道哪行改了,要么全量重渲染把页面卡个几秒,要么直接显示旧的错误数据。

3. 团队协作下的沟通成本会远高于你写拷贝逻辑的成本

所有看到你代码的开发者,看到const [clicks, setClicks] = useState(...)的第一反应,一定是“修改这个状态必须用setClicks”。没有人会知道你是靠旁边那个毫无语义的setUpdateRequired空状态触发重渲染,更不会想到clicks是被就地修改的。
哪天团队成员看到clicks.value的值不对,按照标准的React写法调用setClicks({ ...clicks })把引用换了——你这套就地修改的逻辑会直接变得行为不可预测:因为新的state对象和原来的对象不是同一个引用,你后续再就地改clicks.value的时候,其他地方如果持有旧引用,读到的就永远是旧值。

最后补个你当初想解决的问题的正解

你当初觉得“拷贝逻辑太复杂、大规模数组复制开销大”,现在根本不需要自己手写复杂的深拷贝:React 生态官方推荐的useImmer已经可以让你直接写类似就地修改的语法,底层自动帮你生成结构共享的不可变新对象,既省了手写拷贝的麻烦,又完全符合React的状态更新规则,根本没必要自己手写一套靠空setter触发重渲染的野路子。

内容的提问来源于stack exchange,提问作者Sergey Kolesnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 09:06:03