Passing state between 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 only the core Reactjs features.

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.

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 which 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 –

  1. 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 then 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.

  1. 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 –

That’s the end of this article. We have learned how to pass states between components and 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.

About the Author

akamit

I am Akash Mittal, an overall computer scientist. If you want to guest post, need help in your projects, want to advertise, Feel free to contact me at [email protected]

View All Articles