Управление состоянием нескольких дочерних компонентов - PullRequest
0 голосов
/ 28 января 2019

Я не уверен, лучше ли сохранять состояние внутри отдельного дочернего компонента или родительского.

У меня есть родительский компонент, который будет содержать дочерний компонент, который должен быть в состояниидублируется по требованию.

У меня есть несколько вопросов:

  • Где я могу сохранить состояние для отдельного компонента, находится ли он в самом компоненте или в родительском??

  • Если он находится в дочернем компоненте, как я могу сказать родителю обновить других потомков.

  • Если это в родительском компоненте, какпередать ребенку функцию, которая будет обновлять ITS-состояние, а не родительское состояние?

  • Как получить доступ к каждому состоянию компонентов и сказать ему об изменении на основе другого дочернего состоянияменяется?

В настоящее время я помещаю новый «карточный» компонент в массив, который отслеживает все компоненты, которые мне нужно отобразить на «доске».

Я не могу придумать лучший способ управлятьсостояние всего и как получить доступ к каждому ребенку.У них есть индивидуальный идентификатор?как я могу изменить все их состояния.

  • --------------------- BOARD ----------------------- *
    import React from "react";
    import Card from "./Card";

    export default class Board extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          cards: [<Card />]
        };
      }

      componentDidMount() {}

      createCard() {
        this.state.cards.push(<Card />);
        this.forceUpdate();
      }

      render() {
        return (
          <div id="Board">
            <button onClick={() => this.createCard()}>Create Card</button>
            {this.state.cards.map(card => (
              <Card />
            ))}
          </div>
        );
      }
    }
  • -------------------------- КАРТА ------------------------------ *
 export default class Card extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       active: false
     };
   }

   cardClick = () => {
     this.setState({
       active: !this.state.active
     });
   };

   render(cardClick) {
     return (
       <div>
         {this.state.active ? (
           <div
             className="activeCard"
             id="card"
             onClick={() => this.cardClick()}
           >
             Active
           </div>
         ) : (
           <div
             className="inactiveCard"
             id="card"
             onClick={() => this.cardClick()}
           >
             Inactive
           </div>
         )}
       </div>
     );
   }
 } ```



Ответы [ 3 ]

0 голосов
/ 28 января 2019

Чтобы ответить на ваши вопросы:

Где я могу сохранить состояние для отдельного компонента, находится ли оно в самом компоненте или в родительском?

BestПрактика - хранить состояние в компоненте, который нуждается в нем.Если двум родственным компонентам необходим доступ к одному и тому же состоянию, поднимите его до родителя.

Затем можно передать отдельные реквизиты или передать все состояние с помощью Context Api.Вы можете использовать это для передачи функций для обновления родительского состояния, если это необходимо, и дети будут автоматически получать реквизиты по мере их обновления.


Для вашего конкретного сценария каждая карта должна иметь свое собственное состояниеопределить, активен он или нет.Можно было бы также сохранить массив активных состояний в родительском элементе, но это не так интуитивно понятно и немного сложнее.

Как получить доступ к каждому состоянию компонентов и сказать ему:изменение на основе изменения другого дочернего состояния?

Вы не должны этого делать.Вы должны хранить любую информацию, которой хотите поделиться с другими компонентами родительского элемента.

0 голосов
/ 28 января 2019
Where do i store the state for the individual component is it in the component itself or is it in the parent?

Состояние отдельного компонента должно быть внутри компонента, если это состояние контролируется и требуется только внутри этого компонента.Например: активный (логический) в карте.Поскольку щелчок по карте должен сделать ее выбранной, а также сделать текущую активную карту неактивной, мы можем заключить, что она лучше хранится вне компонента Card в родительском элементе.

If it's in the parent how do I pass a function to the child which will update ITS state and not the parents state?

Вы можете передать эту функцию какprop (после привязки к родителю)

How do I access each of the components state and tell it to change based on another child state changing?

Поскольку вы храните список карт и активный логический элемент в родительском компоненте Board, вам не нужно это делать.

Сохранять подобное состояние вДоска.

this.state = {
   cards: [
     {id: 1, name: 'Card1'},
     {id: 1, name: 'Card2'},
     {id: 1, name: 'Card3'},
   ],
   activeId: 2
}
0 голосов
/ 28 января 2019

Хорошо, давайте возьмем это сверху.Я полагаю, у вас есть данные, которые вы хотите отобразить как <Card />, по одному для каждого элемента данных.Вы не держите компоненты в состоянии, а, скорее, данные.Например:

this.state = {
  data: [
    {value: 'Cat 1'},
    {value: 'Cat 2'},
    {value: 'Cat 3'}
  ] 
} 

В этом случае родитель должен хранить данные правильно.Тем не менее, вся концепция подъема состояния (ссылка React docs) не так уж сложна.В основном, это вопрос: заботится ли более чем один компонент / зависит от одного и того же состояния? Если ответ положительный, обычно родитель должен его содержать.Вы правы в том, что каждая карта имеет свое собственное активное состояние.Тем не менее, родитель мог сделать это также.Тогда давайте сделаем это:

Board.js

import React from 'react';
import {Card} from './Card';    

class Board extends React.Component{
    state = {
      data: [
        {value: 'Cat 1'},
        {value: 'Cat 2'},
        {value: 'Cat 3'}
      ],
      activeCard: null, 
    }
    cardClick = id => {
       this.setState({ activeCard: id })
    }
    addCard = () => {
      const newCard = { value: 'Some val here' };
      this.setState({ data: [...this.state.data, newCard] });
    }
    render(){
      return(
        <div id="Board">
          <button onClick={this.addCard}>Add a card</button>
          {this.state.data.map((item, index) => 
            <Card key={index} 
              value={item.value} 
              active={this.state.activeCard === index}
              cardClick={this.cardClick}
              index={index}
            />
           )}
         </div>
       )
    }
}

export default Board;

Делая это, наш родитель управляет всем.Не сказать, что это единственный правильный путь, но это позволяет нам иметь компонент Card в качестве «тупого», функционального компонента.Будьте осторожны - этот конкретный подход основан на том, что данные никогда не меняются в порядке, поскольку он опирается на индекс .map, который составляет от 0 до длины данных - 1.

Card.js

import React from 'react';

const Card = props => (
    <div
        className={props.active ? 'activeCard' : 'inactiveCard'}
        onClick={() => props.cardClick(props.index)}
    >
        Active
    </div>
);

export { Card };

Есть несколько ключевых различий между тем, что вы опубликовали, и тем, что я сделал.

1) Вы отображали карты с одинаковым id="card", что плохо, идентификатор должен бытьуникальный.Кроме того, если вам это действительно не нужно, вы можете его опустить.

2) Я переключаю className на основе индекса активной карты.Если текущая карта, скажем, 2, также является активной картой, она будет иметь activeCard className.

3) Наконец, я передаю функцию ребенку, которая обновляет состояние родителей.Таким образом, у меня есть состояние, содержащееся в родительском элементе, и каждый раз, когда я обновляю его, оно будет отражаться и на дочерних элементах.Это не значит, что ваш подход к использованию компонентов на основе классов для карт является неправильным, но я думаю, что это проще.

4) Просто выбросить его туда, WAI-ARIA недействительно согласен с div, имеющим onClick событий.Чтобы сделать Интернет классным, доступным местом, вы можете поставить role="button" на div, чтобы обозначить, что это кнопка.Это также требует, чтобы он был фокусируемым, а также слушателем событий клавиатуры, и в этом случае вам, вероятно, лучше просто использовать <button>, если элемент должен быть кликабельным.

Чтобы ответить на другие ваши вопросы:

  • Родитель автоматически передает все изменения состояния всем дочерним элементам, которые заботятся о нем

  • Все дочерние компоненты независимы от родителя, например, если ониесть свои состояния, родителю все равно.Это становится актуальным только тогда, когда они совместно используют функцию состояния и обновления состояния, поэтому только если вы специально передаете такую ​​функцию дочерним элементам

  • Если дочерние элементы совместно используют состояние, тогдаБыть поднятым, что объясняется в документе, связанном!

РЕДАКТИРОВАТЬ : для данного примера я предположил, что вы хотите только одну активную карту за раз.Если это не так, либо пусть каждая карта удерживает свои активные состояния, как предложил Кено Клейтон, либо измените activeCard на массив, сверяя индекс каждой карты с массивом активных карт

...