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

Mobx中changeData3方法无法触发React组件重渲染的原因解析

Mobx状态更新不触发组件重渲染的问题分析

使用changeData1和changeData2方法时,能够触发计算属性并使React组件重新渲染;但使用changeData3方法结合changeObjUtil函数修改时,即使对象是按引用传递的,也无法触发组件重渲染。请问这是什么原因?

Mobx Store代码

class Test {
  data;
  constructor() {
    this.data = { "1": { user: { name: "user0" } } };
    makeAutoObservable(this);
  }

  get getData() {
    return this.data;
  }

  changeData1() {
    const newObj = { user: { name: "user1" } };
    this.data["1"] = newObj;
  }

  changeData2() {
    const newObj = { user: { name: "user2" } };
    const item = this.data["1"];
    item.user.name = newObj.user.name;
  }

  changeData3() {
    const item = this.data["1"];
    const newObj = { user: { name: "user3" } };
    this.changeObjUtil(item, newObj);
  }

  changeObjUtil(obj1, obj2) {
    obj1 = obj2;
  }
}

React组件代码

const t = new Test();

export default observer(function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => t.changeData1()}>changeData1</button>
      <button onClick={() => t.changeData2()}>changeData2</button>
      <button onClick={() => t.changeData3()}>changeData3</button>

      <div>
        {Object.keys(t.getData).map((key) => {
          const item = t.getData[key];
          return <div key={key}>{item.user.name}</div>;
        })}
      </div>
    </div>
  );
});

问题原因

核心问题出在changeObjUtil的赋值逻辑,以及JavaScript的参数传递规则:

  • JavaScript的函数参数是按值传递的——哪怕传递的是对象引用,传递的也只是引用的副本。
  • changeObjUtil里的obj1 = obj2,只是把函数内部的局部变量obj1的指向改成了obj2,但这完全不会影响外部this.data["1"]原本指向的对象。
  • Mobx能追踪状态变化的前提是:要么直接修改被观察对象的属性,要么替换被观察对象的引用。而这里this.data["1"]的引用没变化,其内部属性也没被修改,Mobx感知不到状态变更,自然不会触发组件重渲染。

对比生效的两个方法:

  • changeData1:直接替换了this.data["1"]的引用,Mobx能追踪到这个引用变化。
  • changeData2:直接修改了this.data["1"].user.name这个嵌套属性,Mobx的深度观察能捕捉到这个属性修改。

修复方案

方案1:直接修改原对象的属性

修改changeObjUtil,通过Object.assign把新对象的属性合并到原对象上,这样Mobx能追踪到属性变化:

changeObjUtil(obj1, obj2) {
  Object.assign(obj1, obj2);
}

方案2:返回新对象并替换引用

让changeObjUtil返回新对象,在changeData3中直接替换this.data["1"]的引用:

changeData3() {
  const newObj = { user: { name: "user3" } };
  this.data["1"] = this.changeObjUtil(newObj);
}

changeObjUtil(obj2) {
  return obj2;
}

内容的提问来源于stack exchange,提问作者Eran Abir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:45:42