Even if/when we don’t use directly a context in our projects, most of the popular libraries like Formik, Redux, etc do; and if the used libraries don’t have a solution to bypass the unwanted re-renders issue, we should deal with it ourselves in our components.
I faced a big performance issue lastly due to those re-renders and to fix that, I had to use abusively React.memo, React.useCallback and React.useMemo in a lot of files.
And I was asking my self: what if we can just take out the hook that was causing that issue instead of adding a lot of things in our components?
so the answer was react-hooks-in-callback, a npm package that lets you mount a react hook from a callback and use its state within the callback itself. I will probably write an article on it later, now let’s just focus on the React context re-renders issue with this following example.
Let’s create an index.jsx file where we will define our components (App, Title and Clicks)
App: this component will be the wrapper where we will use our context Provider and implement the click behaviour (at each click event, we will increment the clicks value, while the title value will remain the same)
Title and Clicks: so while the Clicks component will re-render at each click event, the Title one instead should render only once. to check the behaviour we will define in the Title a variable countRef which value is incremented at each re-render.
Initially the component looks like this
then after 10 clicks, we can clearly see that also the countRef value of the Title component has changed even if the title value its self is still the same as before ( => the Title component re-rendered 10 times).
This will create a performance issue if the Title component has a lot of heavy computations in it, so we should fix it: the standard way is to use React.memo, React.useCallback and React.useMemo. but this is a time consuming operation and will increment your lines of codes.
instead we can create a clean context using react-hooks-in-callback package.
so the first step is to install it via this command line:
npm install — save react-hooks-in-callback
now, in order to have a clean context, we can import createContext from react-hooks-in-callback and use it instead of the standard React.createContext
with the new import, there is no need to change the App component, but only the consumer components (Title and Clicks) with a minimal change: we just need to replace useContext with useContextSelector that will help us to pick only the desired state.
in Title: const title = useContextSelector((ctx) => ctx.title);
in Clicks: const clicks = useContextSelector((ctx) => ctx.clicks);
with this change we can now click on the increment button and see how the Title Component behaves
as expected, the Title component did not re-render neither once after 21 clicks.
Now you see how simple it was to come over that issue (no matter how big the component will be, the change is just about to replace the standard React context with the clean one from the react-hooks-in-callback package)
Fernando Ekutsu Moondele
Senior React Frontend developer
my LinkedIn profile