简体   繁体   English

从 React.js 中递归渲染的组件更新状态

[英]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、 itemparentChecked的组件,其中后者是来自父级的布尔值,而前者成为构造函数中的可变状态变量。

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函数: idnewState 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 ,可以像这样调用updateStateupdateState('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"));

Working example.工作示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM