Some months ago, I was refactoring a React project, and I was stuck in one problem for hours. The refactor was because of a common problem in React projects: Pass a lot of props to the child components, then you have to pass them to the child of them, and so. When this happens, if you want to reuse those components on another part of the app, you have to get information in your new component that maybe you don’t need to worry about that time.
Versión en español aquí
I separated the data into many contexts, so I only share the necessary data with the component that needs them. So I stopped to pass a lot of props in every component. Even that sounds like a successful refactor, it wasn’t. My components keep updating when I updated an state of a context which they didn’t depend on. It doesn’t make sense, right?
To explain my problem, I’ll give you an example.
I’ll have 3 components:
SessionForm: Component to add a username. If you have already entered it, it shows a greeting and a button to log out (delete the username). If you haven’t entered it, it shows you an entry to add it.
SessionCounterMessage: Component that shows a message with the username entered or a `You` and the number returned by a counter.
CounterButtons: Component with a counter and 2 buttons that allow you to add or subtract from the counter.
Based on my first solution, I would create 2 contexts. One for the username (
SessionContext) and one for the counter (
CounterContext). Then the dependency of contexts of my components would look like this:
SessionForm depends on
CounterButtons depends on
SessionCounterMessage depends on
This was my initial solution:
I added a
console.log to my components to make you aware of my error, I added a console.log to my components so that they see how many times it was rendered:
There you can see, when I update the counter, it re-renders the
SessionForm component. Even when it doesn’t depend on the
CounterContext context, which has
And when I update the username, it re-renders the
CounterButtons component. Even when it doesn’t depend on the
SessionContext context, which has
username as a state.
Now you see my code, do you find my mistake? Well, I didn’t find any mistakes in my code if I had separated them into different contexts. Why did they keep re-render all the components?
What I did was ask for help. I asked @sergiodxa, who has been using React longer, and he said:
is different from this:
He didn’t explain why at that time; maybe he was busy, I don’t remember. But I realized that I was rendering my component in the same place that I created my states. Every time I updated the state, it re-rendered my parent component, which re-render all its children.
With this in my mind, I’ll change my initial example to check it works.
Here you can see the logs when every component is rendered
It works! No more unnecessary renders!
It could look like a small change, and even you could think the user won’t notice this change. But the components I was refactoring rendered audios and videos. Every time I updated the audios, the videos would be re-rendered, and it looks like a bug in the app.
If you made it this far, thanks for reading. ❤️