[英]Updating state from recursively rendered component in React.js
I am in need of updating deeply nested object in a React state from a recursively rendered component.我需要从递归渲染的组件更新处于 React 状态的深层嵌套对象。 The items look like this and can be nested dynamically:
这些项目看起来像这样并且可以动态嵌套:
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: []
}
]
}
]
I have a problem figuring out how to update the top level state from within a deeply nested component, because it only "knows" about itself, not the entire data structure.我在弄清楚如何从深度嵌套的组件中更新顶级状态时遇到了问题,因为它只“知道”自己,而不是整个数据结构。
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>
);
}
}
How can I achieve this, please?请问我怎样才能做到这一点?
This works in your fiddle you posted.这适用于您发布的小提琴。
Basically, each component needs to know about its item.isChecked
and its parent's isChecked
.基本上,每个组件都需要了解其
item.isChecked
及其父级的isChecked
。 So, create a component that takes 2 props, item
and parentChecked
where the latter is a boolean from the parent and the former becomes an mutable state variable in the constructor.因此,创建一个带有 2 个 props、
item
和parentChecked
的组件,其中后者是来自父级的布尔值,而前者成为构造函数中的可变状态变量。
Then, the component simply updates its checked state in the event handler and it all flows down in the render method:然后,组件简单地在事件处理程序中更新它的检查状态,并在渲染方法中向下流动:
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"));
https://codesandbox.io/s/treelist-component-ywebq https://codesandbox.io/s/treelist-component-ywebq
How about this:这个怎么样:
Create an updateState
function that takes two args: id
and newState
.创建一个带有两个参数的
updateState
函数: id
和newState
。 Since your ids
already tell you what item you are updating: 3, 3.1, 3.1.1
, you can from any of the recursive items call your update function with the id
of the item you want to modify.由于您的
ids
已经告诉您要更新的项目: 3, 3.1, 3.1.1
,您可以从任何递归项目中使用要修改的项目的id
调用更新函数。 Split the id
by dots and go throw your items recursively to find out the right one.用点分割
id
,然后递归地扔掉你的物品以找出正确的物品。
For example from the recursive rendered item 3.1.1
, can call updateState
like this: updateState('3.1.1', newState)
.例如,从递归渲染项
3.1.1
,可以像这样调用updateState
: updateState('3.1.1', newState)
。
import React from "react";
import { render } from "react-dom";
import items from "./items";
class App extends React.Component {
state = {
items
};
updateState = item => {
const idArray = item.id.split(".");
const { items } = this.state;
const findItem = (index, children) => {
const id = idArray.slice(0, index).join(".");
const foundItem = children.find(item => item.id === id);
if (index === idArray.length) {
foundItem.isChecked = !item.isChecked;
this.setState(items);
return;
} else {
findItem(index + 1, foundItem.children);
}
};
findItem(1, items);
};
recursivelyRenderItems(items) {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<input
type="checkbox"
checked={item.isChecked}
onChange={event => this.updateState(item)}
/>
{this.recursivelyRenderItems(item.children)}
</li>
))}
</ul>
);
}
render() {
return <div>{this.recursivelyRenderItems(this.state.items)}</div>;
}
}
render(<App />, document.getElementById("root"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.