Передача состояния между компонентами
Я написал компонент с состоянием 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