How to access childs state from parent component in React

Are you seeking how to access a child state from a parent component?

This is the article you’ve been waiting for!

The answer: Use a callback function

The most common method is to make a callback function that the child component will trigger and toss the state values upward.

Let’s take a look at a couple methods.

Get state value onClick event

One method is to update state, and when a click happens, use a callback function that gives the parent component the values.

Here’s an article that covers this method more in detail, “How to get form data on submit in ReactJS“.

Get state value on onChange event

The method above covers how to pass the child state over a click event.

But what about when input field changes?

We sure can do that as well! Let’s take a look at how.


class ChildComponent extends React.Component {

  state = {
    username: '',
    password: '',
  }

  handleChange = e => {
    this.setState({ [e.target.name]: e.target.value }, () => {
      if (this.props.onChange) {
        this.props.onChange(this.state);
      }
    })
  };

  render() {
    return (
      <>
        <div>
          <div>Username:</div>
          <input name="username" onChange={this.handleChange} />
        </div>
        <br />
        <div>
          <div>Password:</div>
          <input name="password" onChange={this.handleChange} />
        </div>
        <br />
        <div>
          <button onClick={this.handleSubmit}>Submit</button>
        </div>
      </>
    );
  }
}

Let’s take a look at the the code snippet that handles React state update and returns the new state object to the parent component.


state = {
  username: '',
  password: '',
}

handleChange = e => {
  this.setState({ [e.target.name]: e.target.value }, () => {
    if (this.props.onChange) {
      this.props.onChange(this.state);
    }
  })
};

In the handleChange() method, I’m calling this.setState(), and updating the component state object with the new values.

In this.setState(), i’m also passing a function as a second parameter. That function gets called once the React state object has been modified.

In that callback function, I’m checking if the React parent component provided a prop called onChange(), and if so, pass the updated child component state object.

Let’s see how the code looks like in the parent component:


function App() {

  const eventhandler = data => console.log(data)

  return <ChildComponent onChange={eventhandler} />;
}

Fairly simple. As I’m typing I see a log as such:


Object {username: "a", password: ""}
Object {username: "a", password: "s"}
Object {username: "a", password: "ss"}
Object {username: "a", password: "sss"}

Is there a more recommended way after React state has changed?

Yes! Let’s take a look at React's componentDidUpdate lifecycle.

Get state value on React componentDidUpdate

If you’re curious to read up on how React componentDidUpdate works, check out this article, “How does React componentDidUpdate work“.


class ChildComponent extends React.Component {

  state = {
    username: '',
    password: '',
  }

  handleChange = e => this.setState({ [e.target.name]: e.target.value });

  componentDidUpdate() {
    if (this.props.onChange) {
      this.props.onChange(this.state);
    }
  }

  render() {
    return (
      <>
        <div>
          <div>Username:</div>
          <input name="username" onChange={this.handleChange} />
        </div>
        <br />
        <div>
          <div>Password:</div>
          <input name="password" onChange={this.handleChange} />
        </div>
        <br />
        <div>
          <button onClick={this.handleSubmit}>Submit</button>
        </div>
      </>
    );
  }
}

The only change here is to move the callback function in this.setState() onto the componentDidUpdate lifecycle.

This may be a more beneficial approach because:

  • You have access to previous props and state for comparison
  • It’s better suited when React performs batching
  • More consistent code logic

In the example above I demonstrated a class component, what if you’re using a functional component?

You can use the React useEffect hook to emulate componentDidUpdate.

Get state value on React useEffect hook

Here’s how we can pass the state to the parent component with the React useEffect hook:


function ChildComponent(props) {

  const [formData, setFormData] = React.useState({ username: '', password: '' });

  const handleChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });

  React.useEffect(() => {
    if (props.onChange) {
      props.onChange(formData)
    }
  }, [formData.username, formData.password])

  return (
    <>
      <div>
        <div>Username:</div>
        <input name="username" onChange={handleChange} />
      </div>
      <br />
      <div>
        <div>Password:</div>
        <input name="password" onChange={handleChange} />
      </div>
      <br />
    </>
  );
}

Get state with React useRef or createRef

This certainly NOT recommended, but it’s a nice to know.

Before you get the reference from a component, make sure your child component is a class type.

If you try to get the reference from a function component, your code will break.


Type '{ ref: MutableRefObject<any>; }' is not assignable to type 'IntrinsicAttributes & { children?: ReactNode; }'.
  Property 'ref' does not exist on type 'IntrinsicAttributes & { children?: ReactNode; }'

All this really means, is that functional components don’t have an instance. They’re stateless.

But if your child component is a class type, then this is how you get the state from it with React useRef hook or createRef().


function App() {

  const childCompRef = React.useRef(null);

  React.useLayoutEffect(() => {
    console.log(childCompRef)
  }, [])

  return <ChildComponent ref={childCompRef} />;
}

And the output on the console should look like this:


current: ChildComponent
  props: Object
  context: Object
  refs: Object
  updater: Object
  state: Object
    username: ""
    password: ""
  handleChange: function () {}
  _reactInternalFiber: FiberNode
  _reactInternalInstance: Object
  <constructor>: "ChildComponent"

You can then go through the object reference path to get to the state object


childCompRef.current.state // {username: "", password: ""}

The only caveat here is that this only works for the initial state. If your child component state is updated, the reference variable will not be updated with the new values.

Oh wow, you’ve made it this far! If you enjoyed this article perhaps like or retweet the thread on Twitter:

I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!