Reputation: 1387
I wrote a component with a state chosenGenre
and inside it, there is a function that changes the state according to the clicked button.
I would like to take the updated state (which is string
) and use it in another component.
This is the component in which the state is declared:
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>
)
}
}
And this is the new component for which I want to use the chosenGenre
state from GenreSelectPage
component :
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>
)
}
}
What should I change inside the:
<p>Welcome to {GenreSelectPage.state.chosenGenre} room !</p>
So it will work?
Upvotes: 5
Views: 14043
Reputation: 2860
Common parent: ( You can lift your state up one level )
If these components have a common parent, then you need to move this state one step up into the common parent component and pass the handler to update the state into GenreSelectPage
and pass the state has props
into InRoomPage
.
Have no common parent: ( Can use Redux )
You need to use Redux, where you state will be maintained in one central store and you can connect to this store from any component from any part of the component tree and get the state into its props.
usage : https://redux.js.org/basics/usage-with-react
Moving components under the same parent:
You can create a new component say componentParent (Use name according to your app ), store your state in this component.
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>
)
}
}
also please check Context API
Upvotes: 9
Reputation: 3604
As others have mentioned, the common way to share state between components is to use Redux, MobX is another alternative.
Here's a basic example of a Redux application. Two components, one which writes a value to the Redux store, and the other which reads a value from the Redux store.
The key parts of setting up Redux are:
<Provider>
- This wraps your entire app and supplies the store, also known as a reducerconnect
- This function connects your component to redux, its first two arguments are mapStateToProps
, and mapDispatchToProps
mapStateToProps
- This parameter is a function that allows you to read from the state (redux store), and it will put the values into this.props
mapDispatchToProps
- Dispatch actions to update the store is done from hereYour reducer, actions, and selectors are normally in separate files, so they can be shared between components easily.
The components below would be in separate files as well, and you'd export default
the connect
portion of each.
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>
Upvotes: 3
Reputation: 13266
You can try any of the below things
a. Move the state to the common parent component of GenreSelectPage
and InRoomPage
. Pass the handleGenereChange
method to the GenreSelectPage
as props and set the state in the parentComponent
. Send the state value as props to InRoomPage
. This is called lifting the state up. More details at https://reactjs.org/docs/lifting-state-up.html
b. Use Redux. More info available on https://almerosteyn.com/2016/08/redux-explained-again
Upvotes: 1