Обновление состояния из рекурсивно визуализированного компонента в React. js - PullRequest
1 голос
/ 06 марта 2020

Мне нужно обновить глубоко вложенный объект в состоянии 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>
    );
  }
}

Как мне этого добиться, пожалуйста?

Ответы [ 2 ]

0 голосов
/ 06 марта 2020

Как насчет этого:

Создать функцию updateState, которая принимает два аргумента: id и newState. Поскольку ваш ids уже сообщает вам, какой элемент вы обновляете: 3, 3.1, 3.1.1, вы можете из любого из рекурсивных элементов вызвать вашу функцию обновления с id элемента, который вы хотите изменить. Разделите id по точкам и go рекурсивно бросьте ваши предметы, чтобы найти правильный.

Например, из рекурсивного визуализированного элемента 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"));

Рабочий пример.

0 голосов
/ 06 марта 2020

Это работает в вашей скрипке вы опубликовали.

По сути, каждый компонент должен знать о своем item.isChecked и родительском isChecked. Итак, создайте компонент, который принимает 2 подпорки, item и parentChecked, где последний является логическим значением от родителя, а первый становится изменяемой переменной состояния в конструкторе.

Затем компонент просто обновляется его проверенное состояние в обработчике событий, и все это течет вниз в методе рендеринга:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...