Как разделить состояние между дочерними компонентами (братьями и сестрами) в ReactJS?

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

У меня 3 компонента. Внутри Header у меня есть кнопка с функцией onClick для переключения раскрывающегося меню внутри Navigation. И, кстати, хотелось бы передать такое же состояние на AnotherComponent.

Как передать состояние (например, isDropdownOpened) от Header к Navigation и AnotherComponent?

<div>
     <Header />
       <Navigation />
        <div>
          <div>
             <div>
               <AnotherComponent />
             </div>
           </div>
        </div>
</div>

Поднимите состояние до общего предка закрытия и передайте состояние через props. Например, родительский компонент Header, Navigation and AnotherComponent.

Shahram 06.12.2018 10:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
6
1
7 568
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

How to pass state (such as isDropdownOpened) from Header to Navigation and AnotherComponent, please ?

Вы храните состояние в предке Header и передаете это состояние в Haeader, Navigation и AnotherComponent в качестве свойств. См. Состояние и жизненный цикл и Поднятие состояния вверх в документации.

Пример:

const Header = props => (
    <div>
        <span>Header: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

const Navigation = props => (
    <div>
        <span>Navigation: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

const AnotherComponent = props => (
    <div>
        <span>AnotherComponent: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

class Wrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          isDropdownOpened: false
        };
    }
    componentDidMount() {
        setInterval(() => {
            this.setState(({isDropdownOpened}) => {
                isDropdownOpened = !isDropdownOpened;
                return {isDropdownOpened};
            });
        }, 1200);
    }
    render() {
        const {isDropdownOpened} = this.state;
        return (
            <div>
              <Header isDropdownOpened = {isDropdownOpened} />
              <Navigation isDropdownOpened = {isDropdownOpened} />
              <div>
                 <div>
                     <div>
                          <AnotherComponent isDropdownOpened = {isDropdownOpened} />
                     </div>
                 </div>
              </div>
          </div>
        );
    }
}

ReactDOM.render(
    <Wrapper />,
    document.getElementById("root")
);
<div id = "root"></div>

<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Есть и другие опции, которые Арно полезно предоставляет в его ответ.

Спасибо, поднять состояние - это сложно, не так ли? Точно так же мы формируем ввод и форму?

Steffi 06.12.2018 11:00

@Steffi - это один из способов обеспечить единый источник правды для этой информации. если есть другая информация, которую вам нужно хранить таким же образом, вы можете сделать их обоими свойствами объекта, которым вы делитесь через дерево. Тем не менее, смотрите Ответ Арно для получения дополнительных опций. Вы не первый, кто сочтет это громоздким.

T.J. Crowder 06.12.2018 11:06

У вас есть разные подходы к решению этой ситуации.

  • Сохраните состояние в верхнем компоненте и передайте его детям через props
  • Используйте контейнер состояния, чтобы сохранять и делиться состоянием вашего приложения между компонентами (например, https://redux.js.org/)
  • Используйте новую функцию Реагировать на контекст. Контекст предоставляет способ передавать данные через дерево компонентов без необходимости передавать реквизиты вручную на каждом уровне.

Я пробовал React Context, но он не работает, когда это не то же дерево, верно?

Steffi 06.12.2018 12:39

Точно. Контекст предназначен для обмена данными, которые можно считать «глобальными» для дерева компонентов React. Если вам нужен глобальный магазин, вы можете рассмотреть возможность использования Redux.

Arnaud Christ 06.12.2018 14:34

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

class ExampleParentComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        isDropdownOpened: false
    }
  }

  toggleDropdown() {
    this.setState({
        isDropdownOpened: !isDropdownOpened
    });
  }

  render() {
    return (
        <div>
          <Header open = {isDropdownOpened} toggleDropdown = { this.toggleDropdown }/>
          <Navigation open = { isDropdownOpened}/>
          <div>
             <div>
                 <div>
                      <AnotherComponent open = { isDropdownOpened} />
                 </div>
             </div>
          </div>
        </div>
    );
}


class Header extends React.Component {
    render() {
        return (
            <div>
                <button onClick = { this.props.toggleDropdown }>TOGGLE ME</button>
                { isDropdownOpened && (
                    <h1> DROPPED </h1>
                }
            </div>
        );
    }
}

Я не понимаю эту часть кода: <button onClick = { this.props.toggleDropdown } /> - <Header toggleDropdown = { this.toggleDropdown } />, затем toggleDropdown() { this.setState({ isDropdownOpened: !isDropdownOpened }); }. Значит, функция onclick для переключения исходит от родителя?

Steffi 06.12.2018 11:08

при нажатии на кнопку он вызывает props.toggleDropdown, который указывает на функцию, которая переключает isDropdownOpened, при изменении этого значения новое переключаемое значение детализируется до всех компонентов, которые подписываются (?) на это состояние.

Tenzin Kunkyab 06.12.2018 13:06

Да, переключатель исходит от родителя и распространяется на всех дочерних элементов. Вы даже можете сохранить значение в компоненте Header, но чтобы отправить его братьям и сестрам, вам все равно придется создать состояние в ParentComponent и передать значение остальным дочерним элементам. Если мы сделаем это таким образом, не будет единого источника истины, поэтому я передал его Родителю и распространил на всех детей. Но это очень самоуверенный стиль кодирования.

Tenzin Kunkyab 06.12.2018 13:08
Ответ принят как подходящий

Это точная причина, по которой были разработаны (и раскручены сообществом ?) "Реагировать на хуки", но не используйте их еще в производстве, они все еще находятся на ранней стадии разработки (альфа), и их спецификация / реализация могут быть изменены!

Проблему можно решить с помощью замечательного API «Реагировать на контекст», который позволяет передавать данные компонентам независимо от того, насколько глубоко они вложены в дерево. Чтобы познакомиться с контекстом, прочтите обширную документацию по ссылке выше. Я объясню здесь лишь небольшой и быстрый пример:

  1. Создайте компонент контекста и экспортируйте потребителя

App.jsx

import React from "react";

// The initial value can be anything, e.g. primitives, object, function,
// components, whatever...
// Note that this is not required, but prevebents errors and can be used as
// fallback value.
const MyContext = React.createContext("anything");

// This component is the so called "consumer" that'll provide the values passed
// to the context component. This is not necessary, but simplifies the usage and
// hides the underlying implementation.
const MyContextConsumer = MyContext.Consumer;

const someData = { title: "Hello World" };

const App = ({ children }) => (
  <MyContext.Provider value = {someData}>{children}</MyContext.Provider>
);

export { MyContextConsumer };
export default App;
  1. Импортируйте созданного потребителя в любой компонент и используйте предоставленное значение

AnotherComponent.jsx

import React from "react";
import { MyContextConsumer } from "./App";

const AnotherComponent = () => (
  <div>
    <MyContextConsumer>{({ title }) => <h1>{title}</h1>}</MyContextConsumer>
  </div>
);

export default AnotherComponent;
  1. Визуализируйте приложение с обоими компонентами контекста
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";
import AnotherComponent from "./AnotherComponent";

const Root = () => (
  <App>
    <AnotherComponent />
  </App>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<Root />, rootElement);

Компонент отобразит заголовок уровня 1 с текстом «Hello World».

Edit stackoverflow-53648661-how-to-share-state-between-child-component-siblings-in-reactjs

Спасибо!!! Я предпочитаю это решение, но какое будет решение с использованием хуков? Ты можешь это сделать?

Steffi 06.12.2018 11:47

Я пробовал это, но это не работает ... Это не то же самое дерево.

Steffi 06.12.2018 12:27

to <MyContextConsumer> всегда должен находиться внутри <MyContextProvider>, верно?

Steffi 06.12.2018 12:50

Я расширил пример кода и добавил Codesandbox (MVCE). Да, компонент Consumer всегда должен быть заключен в оболочку компонента Provider.

Arctic Ice Studio 21.12.2018 08:17

app и anotherComponent являются родительскими и дочерними, а не братьями и сестрами.

Mohit Singh 08.03.2020 06:18
First Send the data from the first child to the common parent using callback 
function and then send that received data (stored in state in parent component)
to the second child as props.

вы также можете прочитать эту статью - https://www.pluralsight.com/guides/react-communicating-between-components

Вы можете использовать только this.state.variableName для доступа

<ChildComponent data = {this.state.name} />

И передать функции

<ChildComponent data = {this.HandleChange} />

Другие вопросы по теме