我需要从递归呈现的组件中以React状态更新深层嵌套的对象。这些项目看起来像这样,可以动态嵌套:
const items = [
{
id: "1",
name: "Item 1",
isChecked: true,
children: []
},
{
id: "3",
name: "Item 3",
isChecked: false,
children: [
{
id: "3.1",
name: "Child 1",
isChecked: false,
children: [
{
id: "3.1.1",
name: "Grandchild 1",
isChecked: true,
children: []
},
{
id: "3.1.2",
name: "Grandchild 2",
isChecked: true,
children: []
}
]
},
{
id: "3.2",
name: "Child 2",
isChecked: false,
children: []
}
]
}
]
我在解决如何从深层嵌套的组件中更新顶级状态时遇到问题,因为它仅“了解”自身,而不是整个数据结构。
class App extends React.Component {
state = {
items
};
recursivelyRenderItems(items) {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<input type="checkbox" checked={item.isChecked} onChange={(event) => {
// TODO: Update the item's checked status
}} />
{this.recursivelyRenderItems(item.children)}
</li>
))}
</ul>
)
}
render() {
return (
<div>
{this.recursivelyRenderItems(this.state.items)}
</div>
);
}
}
请问我该如何实现?
如何:
创建具有两个参数的updateState
函数:id
和newState
。由于ids
已经告诉您要更新的项目:3, 3.1, 3.1.1
,因此您可以从任何递归项目中使用要修改的项目的id
来调用更新功能。用点将id
分开,然后递归扔出您的物品以找出合适的物品。
例如,从递归渲染项目3.1.1
中,可以这样调用updateState
:updateState('3.1.1', newState)
。
这对您发布的小提琴有效。
[基本上,每个组件都需要了解其item.isChecked
和其父级的isChecked
。因此,创建一个包含2个props的组件,item
和parentChecked
,其中后者是父对象的布尔值,前者成为构造函数中的可变状态变量。
然后,该组件仅在事件处理程序中更新其检查状态,并且全部在render方法中向下流动:
import React from "react";
import { render } from "react-dom";
import items from "./items";
class LiComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
item: props.item
}
}
render() {
var t = this;
return (
<ul>
<li key={t.state.item.id}>
{t.state.item.name}
<input
type="checkbox"
checked={t.state.item.isChecked || t.props.parentChecked}
onChange={event => {
t.setState({item: {...t.state.item, isChecked: !t.state.item.isChecked}})
}}
/>
</li>
{t.state.item.children.map(item => (
<LiComponent item={item} parentChecked={t.state.item.isChecked}/>
))}
</ul>
);
}
}
class App extends React.Component {
state = {
items
};
render() {
return (
<div>
{this.state.items.map(item => (
<LiComponent item={item} parentChecked={false} />
))}
</div>
);
}
}
render(<App />, document.getElementById("root"));