javascript - 更新数组中组件的 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
确实有孩子,但是当我放入useEffect
时MyChildComponent
,道具改变时它不会触发。(此外,我们使用一个数组来存储我们的组件,因为用户在工作流程中前进,因此使用handleClickNextButton
. 这是一个代码沙箱。
问题是,当我更改 的子组件中的数据时MyChildComponent
,我会将新数据传递给父组件,并且状态已更改,但子组件未接收到新数据。我有预感为什么,但我不喜欢这个解决方案,我在这里发帖看看我是否遗漏了什么(希望能找到更好的解决方案)。
我认为问题在于我希望更改子组件的道具,因为我传入了一个状态变量。它没有改变的原因是因为它在一个数组中(顺便说一句,我确实尝试向数组中的元素添加关键道具,但这并没有解决问题)。一种解决方案是在每次此值更改时重建数组。我不喜欢这个有两个原因:
- 在每次重新渲染时重建数组似乎效率很低
- 这是反直觉的。我希望它的行为有点像 lambda,我可以访问定义 lambda 的范围内的变量(即,您可以像
foo
在 lambda 内一样获得全局变量)。我想在构建数组时“设置”这些值是有道理的,但我想知道是否有人可以提供一个技术原因,为什么这是不可能的。
谢谢 :)
解决方案
您认为问题在于您的阵列状态是正确的。正如在这个相关问题中提到的,您需要将反应状态对象视为不可变的。由于在您的代码中,您直接使用 修改数组.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中的一个例子
推荐阅读
- javascript - 防止 Postgres 中的冲突更新
- javascript - 使用 toDataURL 编写从画布生成的 png,然后通过 NodeJS/Express 中的 XMLHttpRequest 发送
- azure - 从 API 管理服务调用 CosmosDB 的存储过程
- android - 如何在recyclerview中一次只显示一个列表项?
- vue.js - vuelidate 中集合验证的奇怪行为
- typescript - 如何创建一个“代理”对象的类?
- javascript - 构建 Web 组件时未编译 Material Design | 对微前端的思考
- c# - 如何为LINQ中的每组产品制作一组动态过滤器
- mysql - 查询 MySql 视图时出现 SQLGrammar 错误
- windows - 如何重新配置 RabbitMQ 不在 Windows 上使用 %appdata%?