首页 > 解决方案 > 更新数组中组件的 Props

问题描述

我有一个包含一组组件的组件,但似乎数组中的组件并没有改变它的道具。

这是父级的简化示例:

const MyParent = () => {
  const [foo, setFoo] = useState();
  const [viewStack, setViewStack] = useState([]);

  const handleDataChange = (newData) => {
    const newData = {
      ...foo,
      newData,
    }

    setFoo(newData);
  }

  const handleNextButton(key) {
    const currentViewStack = viewStack;
    switch(key) {
      (... several other cases here)
      case theValueWeWant:
        currentViewStack.push(<MyChildComponent myData={foo} dataChangeHandler={handleDataChange} />);
        break;
    }

    setViewStack(currentViewStack);
  }

  return ({viewStack[viewStack.length - 1]});
  
}

这是孩子的一个简化示例:

const MyChildComponent = (props) => {
  const [bar, setBar] = useState();

  useEffect(() => {
    setBar(props.myData);
  }, [props.myData]);
  
  return (
    <div>
      {bar}
      <button onClick={() => { props.dataChangeHandler('my new value'); }}>Click me</button>
    </div>
  );
};

值得注意的是,MyChildComponent确实有孩子,但是当我放入useEffectMyChildComponent,道具改变时它不会触发。(此外,我们使用一个数组来存储我们的组件,因为用户在工作流程中前进,因此使用handleClickNextButton. 这是一个代码沙箱

问题是,当我更改 的子组件中的数据时MyChildComponent,我会将新数据传递给父组件,并且状态已更改,但子组件未接收到新数据。我有预感为什么,但我不喜欢这个解决方案,我在这里发帖看看我是否遗漏了什么(希望能找到更好的解决方案)。

我认为问题在于我希望更改子组件的道具,因为我传入了一个状态变量。它没有改变的原因是因为它在一个数组中(顺便说一句,我确实尝试向数组中的元素添加关键道具,但这并没有解决问题)。一种解决方案是在每次此值更改时重建数组。我不喜欢这个有两个原因:

  1. 在每次重新渲染时重建数组似乎效率很低
  2. 这是反直觉的。我希望它的行为有点像 lambda,我可以访问定义 lambda 的范围内的变量(即,您可以像foo在 lambda 内一样获得全局变量)。我想在构建数组时“设置”这些值是有道理的,但我想知道是否有人可以提供一个技术原因,为什么这是不可能的。

谢谢 :)

标签: javascriptreactjsreact-hooks

解决方案


您认为问题在于您的阵列状态是正确的。正如在这个相关问题中提到的,您需要将反应状态对象视为不可变的。由于在您的代码中,您直接使用 修改数组.push(),因此状态对象未正确更新。

这里的关键是,每当您更新存储在 React 状态中的对象或数组时,您需要在设置新状态之前创建一个全新的对象或数组。

例如:

// === arrays ===
const [nums, setNums] = useState([])

// ...some code

const newNumToAddToList = 3
setNums([ ...nums, newNumToAddToList ])
// ===============

// === objects ===
const [data, setData] = useState({ initialProp: 3 })

// ...some code

const newDataProperty = 'a string value'
setData({ ...data, newProp: newDataProperty })

// or...
const newInitialPropValue = 29
setData({ initialProp: newInitialPropValue })

作为旁注,我强烈建议您不要React 组件存储在状态中。实现目标的一种更简洁的方法可能是将基础数据存储在状态中 -labels在您的代码沙箱示例中。然后,您可以将这些标签映射到 render 方法中的组件中。这是codesandbox中的一个例子


推荐阅读