A Simple Way to Get Child State in the Parent Component Without Unnecessary Renders

Fare warning: You need to know about React to understand this post. The problems and solutions exposes here are all using the modern react approach: Hooks.

This Post is for all those React programmers that have been cross with one particular situation.

The problem:

Imagine your are building a parent component (lets call it “PARENT”), and inside that parent component you have a child component (lets call it “CHILD”). The “PARENT” component has a button, that when it’s clicked, you have to collect the internal state of “PARENT” and “CHILD” components to do something with it, like send the data/state to POST API endpoint to save it on a data base.

Possible solutions:

1- Elevating the state: The most common solution is to manage the state of the “CHILD” in the “PARENT” component, so in “PARENT” you have to manage it’s own state and his “CHILD” state. This can be a problem, because you are coupling this components and overloads the responsibility and state management on the “PARENT” component, making it more difficult to test, re-use and maintain.

2- Global State: Uses some mechanism to manage all the state from a third party library such as Redux or using Context. With this approach we remove the problems from the first solution, because it elevates the state management to a global place, but if we need to know the state of “CHILD” inside “PARENT” component, we need to subscribe “PARENT” to the global state that manage the “CHILD” state component, and while we do that, we create a more complex code, leaving one problem that where present on the first approach too: Every time the “CHILD” component change it’s state, the “PARENT” component will re-render too, and if you are not careful, all his children's will re-render as well (you can avoid that last part with React.memo() on other children's, but that is for other post).

See how the parent component renders when the child changes his state. Observe the counter on the text inputs.

The solution to the rescue:

For this particular situation, the “CHILD” component should manage its own state, and in a particular moment, the “PARENT” must have access to that “CHILD” state, but when the “CHILD” state changes, it can’t trigger a re-render on the “PARENT” component. Achieving that, all our problems would be solved. The good news is that we can!

How to do it with a different approach?

3- Using references: To solve this, we are going to use Hooks and fordwardRef. It’s necessary that in order to work, you need React ≥v16.8. If you are not familiar with Hooks, you should give it a try.

What we need to do in the “PARENT” is to pass a reference (lets call it “childStateRef”) to the “CHILD” component via props. That reference needs to be created on “PARENT” using the useRef() hook. That “childStateRef” is going the be the one that will have the “CHILD” state whenever we need it on the “PARENT” component. See the code below.

The “childStateRef” is passed via props to “CHILD” and used on getChildState function to get the state of “CHILD” on a button click event.

On the “CHILD” component, making use of a combination with React.fordwardRef and the useImperativeHandle() hook we have a way of provide to the received reference a method that returns the internal state of the “CHILD” component. See the code below.

The reference (_ref) on the “CHILD” received from the “PARENT” through React.fordwardRef() and the useImperativeHandle() Hook to allow get the state from the “PARENT”.

This is it, We did it!

Applying the third solution. Note that the “PARENT” doesn’t render when the “CHILD” changes its state. Observe the counter on the text inputs

The code shown until now is a simple way to resolve this problem , but is not the real code used on the examples showed on animated gif. If you want to see the real code you can check this GitHub repository.

And if you want to see the entire application running with all the three examples, and without fork or pull the the entire code and running it yourself on your local environment, you can check this link where it is deployed. Tip: Check your developer console, it will help you to see the amount of renders on each component for each of the three solutions.

Conclusions

In my personal opinion, this last proposal solution is the best option for some specific situations, because it avoids unnecessary renders mainly on the parent, and when we have heavy components, this can be a huge performance improvement. Also, with this last approach, you can let the state management of each component on the component itself, allowing you to have a cleaner code to test, maintain, read and understand.

I'm a Full Stack Web Developer with 10 years of experience. I have dedicated my live to web and mobile experiences.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store