数组属性更改时,React子组件不会重新渲染

时间:2019-10-27 04:47:22

标签: javascript reactjs react-hooks

我的主应用带有两个子组件,两个子组件都具有相同的model属性。

第一个子组件处理model.myNumberProperty中的数字道具,第二个子组件处理model.myArrayProperty中的数字道具

在子组件1中更改model.myNumberProperty会触发重新渲染,但是 不能更改子组件2中的model.myArrayProperty

function App() {
  const model = MyModel();

  return (
    <div className="App">
      Main app
      <ComponentOne dataObject={model} />
      <ComponentTwo dataObject={model} />
    </div>
  );
}

export default function MyModel() {
  let _propOne = 0;
  let _propTwo = ["one"];

  const propOne = () => {
    return _propOne;
  };
  const propTwo = () => {
    return _propTwo;
  };

  const modifyPropOne = () => {
    _propOne++;
    console.log("modifying prop one", _propOne);
  };

  const modifyPropTwo = () => {
    _propTwo.push("new element");
  };

  return Object.freeze({ propOne, propTwo, modifyPropOne, modifyPropTwo });
}


const ComponentOne = props => {
  const [propOne, setPropOne] = useState(props.dataObject.propOne());

  const onButtonOneClick = () => {
    props.dataObject.modifyPropOne();
    setPropOne(props.dataObject.propOne());
  };

  return (
    <div>
      <p>Hello ComponentOne:</p>

      <button onClick={onButtonOneClick}>ModifyPropOne</button>
      <p>{propOne}</p>
    </div>
  );
};

const ComponentTwo = props => {
  const [propTwo, setPropTwo] = useState(props.dataObject.propTwo());

  const onButtonTwoClick = () => {
    props.dataObject.modifyPropTwo();
    setPropTwo([...props.dataObject.propTwo()]);
    console.log('Prop two', props.dataObject.propTwo());
  };
  return (
    <div>
      <p>Hello ComponentTwo</p>

      <button onClick={onButtonTwoClick}>ModifyPropTwo</button>
      {propTwo.map((value, index) => (
        <p key={index}>{value}</p>
      ))}
    </div>
  );
};

请查看this CodeSandbox进行测试。

我正在使用React Hooks。 解决我的问题的方法只能是React,所以不能使用Redux或其他第三方库。

请注意,我的模型是冻结对象以执行封装,因此我不能只是重新创建整个对象。该示例中的模型是简化后的模型,在我的真实项目中,它是一个复杂的Card游戏对象,可以处理许多数组。

1 个答案:

答案 0 :(得分:2)

在调用setState时,React使shallow comparison处于先前的状态,并决定是否应继续进行渲染阶段。

在您的情况下,它具有相同的引用,因此不会触发渲染。

要修复此问题,请将阵列的副本设置为新状态。

const onButtonTwoClick = () => {
  props.dataObject.modifyPropTwo();
  //                v Make a new copy.
  setPropTwo([...props.dataObject.propTwo()]);
};

请参阅The power of not mutating Data

Edit updateArrayProp