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.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Designing a Scalable Redux Architecture for Large Scale Websites

Node JS Error Handling: How and Why Bother?

@blueonion16 ?Congratulations! You WON a $25 Starbucks Coffee Card!

React JS Developers need to read it| Definition | Features, And Installation

Building the future of Moneyfarm UI

Functional Programming with TypeScript — Part 1

Async / Await Components

Skeleton Damage Animation

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
Adrian Fernandez

Adrian Fernandez

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

More from Medium

React Modal Component Implementation

What are CSS Modules and how to use it in React

classComponent Vs functionalComponent

How does useImperativeHandle() work? — React source code walkthrough