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

React中两组件共享同一实例却独立更新的原因咨询

React组件共享实例不同步更新的原因及解决办法

我是React新手,想让两个MyComponent组件共享同一个MyCustomPrototype实例。原本以为点击任意组件的“Click me”按钮后,两个组件里的<p>{myInstance.myProperty}</p>会同步更新,毕竟App里传的是同一个实例,但实际两个组件是独立更新的,求解释原因。

相关代码如下:

import React, { useState } from 'react';

function MyCustomPrototype() {
  this.myProperty = 0;
}

MyCustomPrototype.prototype.handleClick = function () {
  this.myProperty += 1;
};

function MyComponent(prop) {
  const [myInstance, setMyInstance] = useState(prop.myCust);

  function handleClick() {
    myInstance.handleClick();
    setMyInstance(Object.create(myInstance, {
      constructor: {
        value: MyCustomPrototype,
        enumerable: false,
        writable: true,
        configurable: true,
      },
    }));
  }

  return (
    <div>
      <p>{myInstance.myProperty}</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

function App() {
  let myCust1 = new MyCustomPrototype();
  return (
    <div className="App">
      <MyComponent myCust={myCust1} />
      <MyComponent myCust={myCust1} />
    </div>
  );
}
export default App;

问题根源

  • 组件内部useState的状态隔离:每个MyComponent都通过useState(prop.myCust)初始化了自己的本地状态,两个组件各自持有myInstance的引用副本。虽然初始时指向同一个实例,但后续的状态更新是组件内部独立的,互不影响。
  • Object.create生成新引用:点击按钮时,你用Object.create(myInstance)创建了一个全新的对象,它继承自原实例,但属于新的引用地址。此时当前组件的myInstance状态被更新为这个新对象,而另一个组件的状态仍指向原实例,所以不会同步更新。
  • 引用类型内部修改无法触发React更新:就算直接修改原实例的myProperty,另一个组件也不会重新渲染。因为React只有在组件的状态或props引用发生变化时才会触发更新,而实例内部属性的修改属于引用类型的内部变更,React无法自动检测到这种变化。

解决办法

方法1:将共享状态提升到父组件

把实例的管理和更新逻辑放到父组件(App)中,子组件只负责接收props并触发更新:

import React, { useState, useCallback } from 'react';

function MyCustomPrototype() {
  this.myProperty = 0;
}

MyCustomPrototype.prototype.handleClick = function () {
  this.myProperty += 1;
};

function MyComponent({ myInstance, onUpdate }) {
  return (
    <div>
      <p>{myInstance.myProperty}</p>
      <button onClick={onUpdate}>Click me</button>
    </div>
  );
}

function App() {
  const [myCust1, setMyCust1] = useState(new MyCustomPrototype());
  
  const handleUpdate = useCallback(() => {
    myCust1.handleClick();
    // 创建新实例触发React状态更新
    setMyCust1(Object.create(myCust1, {
      constructor: {
        value: MyCustomPrototype,
        enumerable: false,
        writable: true,
        configurable: true,
      },
    }));
  }, [myCust1]);

  return (
    <div className="App">
      <MyComponent myInstance={myCust1} onUpdate={handleUpdate} />
      <MyComponent myInstance={myCust1} onUpdate={handleUpdate} />
    </div>
  );
}
export default App;

父组件的状态更新会同步传递给两个子组件,点击任意按钮都会触发父组件状态变更,进而让两个子组件重新渲染,显示最新的myProperty值。

方法2:使用Context共享状态

如果组件层级较深,使用Context可以避免props层层传递,更方便地共享状态:

import React, { useState, useCallback, createContext, useContext } from 'react';

const InstanceContext = createContext();

function MyCustomPrototype() {
  this.myProperty = 0;
}

MyCustomPrototype.prototype.handleClick = function () {
  this.myProperty += 1;
};

function MyComponent() {
  const { myInstance, onUpdate } = useContext(InstanceContext);
  return (
    <div>
      <p>{myInstance.myProperty}</p>
      <button onClick={onUpdate}>Click me</button>
    </div>
  );
}

function App() {
  const [myCust1, setMyCust1] = useState(new MyCustomPrototype());
  
  const handleUpdate = useCallback(() => {
    myCust1.handleClick();
    setMyCust1(Object.create(myCust1, {
      constructor: {
        value: MyCustomPrototype,
        enumerable: false,
        writable: true,
        configurable: true,
      },
    }));
  }, [myCust1]);

  return (
    <InstanceContext.Provider value={{ myInstance: myCust1, onUpdate: handleUpdate }}>
      <div className="App">
        <MyComponent />
        <MyComponent />
      </div>
    </InstanceContext.Provider>
  );
}
export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:47:28