Passing state between parent and children components is a common use case. Generally, we use a state management library like Redux, for this purpose. But sometimes this is just an overkill. For small applications, we don’t require external state management libraries.
In this article, I will show you how passing of state is done by using the core Reactjs features only.
Pass State from Parent to Children
Since a child component is within the parent component, so we can pass the state as props of child. Look at this code –
export default class Parent extends React.Component{ state = { name: 'Thor', home: 'Asgard', }; render(){ return( <div> <p> Change Parent State - <br /> Name: <input type={'text'} value={this.state.name} onChange={(e) => this.setState({name: e.target.value})} /> home: <input type={'text'} value={this.state.home} onChange={(e) => this.setState({home: e.target.value})} /> </p> <Child parentState={this.state} /> </div> ) } } class Child extends React.Component{ state = { brother: 'Loki', job: 'Being Awesome', } render(){ return ( <div> <p> Change Child State - <br /> Brother: <input type={'text'} value={this.state.brother} onChange={(e) => this.setState({brother: e.target.value})} /> Job: <input type={'text'} value={this.state.job} onChange={(e) => this.setState({job: e.target.value})} /> </p> <p> (Parent State Passed to Child) <br /> Name: {this.props.parentState.name} <br /> Home: {this.props.parentState.home} </p> <p> (Child State) <br /> Brother: {this.state.brother} <br /> Job: {this.state.job} </p> </div> ) } }
Here we have two components – Parent
and Child
. We are passing Parent
state to the Child
using a prop parameter parentState
. If we make changes to the values of parent state, it will get reflected in the rendered JSX of child.
See this code in action from below demo –
Try to make changes in the input fields of above demo, you will see that changes will get reflected in the text. Although, name
and home
input fields are in parent
component yet their values are passed to the child.
You may also like –
Pass State from Children to Parent
In order to pass anything from children to parent, we need to use the callbacks. Look at this code –
export default class Parent extends React.Component{ state = { name: 'Thor', home: 'Asgard', brother: 'Loki', job: 'Being Awesome', }; childStateCallback = (childState) => { this.setState({ brother: childState.brother, job: childState.job, }); } render(){ return( <div> <p> Change Parent State - <br /> Name: <input type={'text'} value={this.state.name} onChange={(e) => this.setState({name: e.target.value})} /> home: <input type={'text'} value={this.state.home} onChange={(e) => this.setState({home: e.target.value})} /> </p> <p> (Parent State Data) <br /> Name: {this.state.name} <br /> Home: {this.state.home} </p> <p> (Child State passed to parent) <br /> Brother: {this.state.brother} <br /> Job: {this.state.job} </p> <Child toCallBack={(childState) => this.childStateCallback(childState)} /> </div> ) } } class Child extends React.Component{ state = { brother: 'Loki', job: 'Being Awesome', } setStateAndRunCallback = (val) => { this.setState(val, () => { this.props.toCallBack(this.state); }); } render(){ return ( <div> <p> Change Child State - <br /> Brother: <input type={'text'} value={this.state.brother} onChange={(e) => this.setStateAndRunCallback({brother: e.target.value})} /> Job: <input type={'text'} value={this.state.job} onChange={(e) => this.setStateAndRunCallback({job: e.target.value})} /> </p> </div> ) } }
In this code we have created a childStateCallback
function in Parent
component. It is getting called from Child
component whenever its state gets updated.
Pay attention that we are using the second parameter of this.setState
to call our callback function. This second parameter ensures that our callback will run after the state gets updated successfully.
Also we are sending the child state directly to the parent which is a wrong practice. We should always send the copy of the state so that there is no risk of state mutation (Learn more about state mutation here). But in our example we are not modifying the child state from parent so its completely safe.
Let’s check out this code in demo –
Calling Child Component Functions from Parent Component
With the help of reference variable, you can call child component function from parent component. Let’s understand this with the help of code –
- Class Based Components
export default class Parent extends React.Component{ constructor(props){ super(props); this.childRef = React.createRef(); } changeChildState = () => { this.childRef.current.functionOfChildComponent('Loki'); } render(){ return( <div> <button onClick={this.changeChildState}>This button press will update child state</button> <Child ref={this.childRef} /> </div> ) } } class Child extends React.Component{ state = { king: 'Thor', } functionOfChildComponent = (newKing) => { this.setState({king: newKing}); } render(){ return ( <div> <p> {this.state.king} is the real king of Asgard. </p> </div> ) } }
Here we are creating a reference variable this.childRef
using React.createRef()
function. This is used as ref
to the Child
component. Now with the click of button, we are calling a child method functionOfChildComponent
and passing a value, ‘Loki’. This way we are accessing child function from parent component.
- Functional Component – Calling through reference is a bit tricky in functional components since they do not support references. But we can get the work done by forwarding refs. Look at the code –
export default function Parent(){ const childRef = React.useRef(); const changeChildState = () => { childRef.current.functionOfChildComponent('Loki'); } return( <div> <button onClick={changeChildState}>This button press will update child state</button> <Child ref={childRef} /> </div> ) } const Child = React.forwardRef((props, ref) => { const [king, setKing] = React.useState('Thor'); React.useImperativeHandle(ref, ()=>({ functionOfChildComponent: (newKing) => { setKing(newKing); } })); return ( <div> <p> {king} is the real king of Asgard. </p> </div> ) });
Let’s understand this code, step by step –
Step 1: Create Reference Variable
In functional component we can use useRef()
hook to create reference variable. In our code, we have created childRef
.
Step 2: Use ref in Child component
We are referring our Child component with childRef
variable in this line <Child ref={childRef} />
.
Step 3: Enclose Child component in React.forwardRef function.
In this step we are simply enclosing our child component in React.forwardRef. So, suppose your component is like this –
const Component = (props) => {}
then after enclosing inside React.forwardRef, it will look like this –
const Component = React.forwardRef( (props, ref) => {} )
You can see that we have added ref
as parameter along with props
. This is important.
Step 4: Use React.useImperativeHandle
function and list all the functions you wish to call as reference.
React.useImperativeHandle basically use the ref variable to make a link between reference variable and functions to be called. So, if your code is this –
const Component = (props) => { const functionToBeCalled = () => {} }
then after using React.useImperativeHandle, it will look like this –
const Component = React.forwardRef( (props, ref) => { const functionToBeCalled = () => {} React.useImperativeHandle(ref, ()=>({ functionToBeCalled: () => functionToBeCalled(), })); } )
Now check the whole working code in this demo –
Live Demo
Conclusion
That’s the end of this article. We have learned how to pass states between parent and child components. We also saw how to call functions of children from parent. Hope this information help you in your projects. If you have doubts or suggestions, please do let me know in comments. See you in the next article.