Передача состояния между компонентами

Я написал компонент с состоянием chosenGenre и внутри него есть функция, которая изменяет состояние в соответствии с нажатой кнопкой.

Я хотел бы взять обновленное состояние (которое string) и использовать его в другом компоненте.

Это компонент, в котором объявлено состояние:

import React, { Component } from 'react';
import Genre from './Genre';
import './GenreSelectPage.css';
import Blues from '../Blues.png';
import Classical from '../Classical.png'; 
import Country from '../Country.png';

export default class GenreSelectPage extends Component{

    state = {
        chosenGenre: ""
    }

    handleClick = (genreName) => {
        this.setState({ chosenGenre: genreName });
    }

    render() {
        return(
        <div className = "GenreSelectPage">
        <h3>Select your desired Kollab Room Genre</h3>
        <Genre genrePicture= {Blues} genreClicked = {()=>this.handleClick("Blues")}/>
        <Genre genrePicture= {Classical} genreClicked = {()=>this.handleClick("Classical")}/>
        <Genre genrePicture= {Country} genreClicked = {()=>this.handleClick("Country")}/>
        </div>
        ) 
     }
}

И это новый компонент, для которого я хочу использовать chosenGenre состояние от GenreSelectPage составная часть:

import React, { Component } from 'react';
import GenreSelectPage from './GenreSelectPage';

export default class InRoomPage extends Component {

    render() {
        return(
            <div className = "InRoomPage">
                <p>Welcome to {GenreSelectPage.state.chosenGenre} page</p>
            </div>
        )
    }
}

Что я должен изменить внутри:

<p>Welcome to {GenreSelectPage.state.chosenGenre} room !</p>

Так будет работать?

3 ответа

Общий родитель: (Вы можете поднять свое состояние на один уровень вверх)

Если эти компоненты имеют общего родителя, то вам нужно переместить это состояние на один шаг вверх в общий родительский компонент и передать обработчик для обновления состояния в GenreSelectPage и пройти государство props в InRoomPage,

Не иметь общего родителя: (Может использовать Redux)

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

использование: https://redux.js.org/basics/usage-with-react

Перемещение компонентов под одним и тем же родителем:

Вы можете создать новый компонент, скажем, componentParent (использовать имя в соответствии с вашим приложением), сохранить свое состояние в этом компоненте.

import React, { Component } from 'react';
import GenreSelectPage from './GenreSelectPage';
import InRoomPage from './InRoomPage';

export default class componentParent extends Component {

    state = {
      chosenGenre: ""
    }

    handleClick = (genreName) => {
      this.setState({ chosenGenre: genreName });
    }

    render() {
      return(
        <div className = "InRoomPage">
          <GenreSelectPage clickHandler={this.handleClick}></GenreSelectPage>
          <InRoomPage chosenGenre={this.state.chosenGenre}></InRoomPage>
        </div>
      )
    }
}

Также, пожалуйста, проверьте контекст API

Как уже упоминалось, общий способ разделения состояния между компонентами заключается в использовании Redux, MobX является еще одной альтернативой.

Вот базовый пример приложения Redux. Два компонента, один из которых записывает значение в хранилище Redux, а другой - считывает значение из хранилища Redux.

Ключевые части настройки Redux:

  • <Provider> - Это оборачивает все ваше приложение и снабжает магазин, также известный как редуктор
  • reducer - здесь вы устанавливаете начальное состояние и возвращаете обновленную версию состояния на основе действий.
  • действия - действия - это просто объекты со значениями, которые вы можете прочитать, чтобы обновить и вернуть новое состояние
  • connect - Эта функция соединяет ваш компонент с Redux, его первые два аргумента mapStateToProps, а также mapDispatchToProps
  • mapStateToProps - Этот параметр является функцией, которая позволяет вам читать из состояния (избыточное хранилище), и он помещает значения в this.props
  • mapDispatchToProps - Отправка действий по обновлению магазина производится отсюда

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

Компоненты ниже также будут в отдельных файлах, и вы export default connect часть каждого.

демонстрация

const { Component } = React;
const { applyMiddleware, createStore } = Redux;
const { connect, Provider } = ReactRedux;


/*********************/
/** GenreSelectPage **/
/*********************/
class GenreSelectPage extends Component {
  constructor(props) {
    super(props);
    this.selectGenre = this.selectGenre.bind(this);
  }
  selectGenre(e) {
    const genre = e.target.value;
    this.props.selectGenre(genre);
  }
  render() {
    return (
      <div>
        <h3>GenreSelectPage Component</h3>
        <select onChange={this.selectGenre}>
          <option value="">Select a genre</option>
          <option value="blues">Blues</option>
          <option value="classical">Classical</option>
          <option value="country">Country</option>
        </select>
      </div>
    )
  }
}

// Write to store
const mapDispatchToProps = (dispatch) => ({ selectGenre: (genre) => dispatch({type: 'SELECT_GENRE', genre}) })

// Connect to store
const GenreSelectComponent = connect(null, mapDispatchToProps)(GenreSelectPage);


/*******************/
/**  InRoomPage   **/
/*******************/
class InRoomPage extends Component {
  render() {
    return (
      <div>
        <h3>InRoomPage Component</h3>
        <p>{this.props.genre}</p>
      </div>
    )
  }
}

// Read from store
const mapStateToProps = (state) => ({ genre: state.genre });
// Connect to store
const InRoomComponent = connect(mapStateToProps)(InRoomPage);

/*******************/
/**     REDUX     **/
/*******************/
const INITIAL_STATE = {
  genre: null
}
const reducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case 'SELECT_GENRE':
      return {
        ...state,
        genre: action.genre
      }
    default:
      return state;
  }
};
const store = createStore(reducer);

// Provider (from Redux) wraps around your entire app
ReactDOM.render(
  <Provider store={store}>
    <GenreSelectComponent />
    <InRoomComponent />
  </Provider>,
  document.getElementById('root')
);
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/6.0.0/react-redux.min.js"></script>
<div id="root"></div>

Вы можете попробовать любую из следующих вещей

а. Переместить состояние в общий родительский компонент GenreSelectPage а также InRoomPage, Пройти handleGenereChange метод к GenreSelectPage в качестве реквизита и установить состояние в parentComponent, Отправить значение состояния в качестве реквизита InRoomPage, Это называется поднятием состояния. Более подробная информация на https://reactjs.org/docs/lifting-state-up.html

б. Используйте Redux. Более подробная информация доступна на https://almerosteyn.com/2016/08/redux-explained-again

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