I am trying to understand this (mostly very helpful) article which describe how to use react's context API to manage application-level state. For a simple application (in this case a basic counter application), it uses the following solution:
const CountContext = React.createContext()
function CountProvider(props) {
const [count, setCount] = React.useState(0)
const value = React.useMemo(() => [count, setCount], [count])
return <CountContext.Provider value={value} {...props} />
}
to provide the context, and then the following hook which can be used in a component somewhere down the component tree:
function useCount() {
const context = React.useContext(CountContext)
if (!context) {
throw new Error(`useCount must be used within a CountProvider`)
}
return context
}
I'm struggling to understand why the useMemo
hook is needed here. There is no especially heavy computation involved here so I'm not sure why we're memoizing these values. Wouldn't this work just as well if the context provider looked as follows:
function CountProvider(props) {
const [count, setCount] = React.useState(0)
return <CountContext.Provider value={value} {...props} />
}
I feel like there is probably something that I'm missing!!
There is a very simple theory to why should use useMemo to memozie the values returned to the Context Provider. When you pass the value to context provider either as an object or as an array like
return <CountContext.Provider value={{state, setCount}} {...props} />
or
return <CountContext.Provider value={[state, setCount]} {...props} />
What essentially happens is that everytime the CountProvider component re-renders a new reference to object or array is being passed as value to CountContext.Provider
and hence even if the actual value may not have changed, the Context consumers are re-rendered since the reference check fails for the value
Now you may or may not need a useMemo depending on what logic you have in your ContextProvider
. For instance, in your case the CountContext
is just using one state i.e count and passes it on to the child and if the CountContext
is one of the top level element which is not re-rendered by anything other than the count change then in that case whether you use useMemo
or not makes no difference since the reference of the returned value from useMemo
is also updated on count change
However if you have certain parents to CountProvider
which can cause CountProvider
to re-render, useMemo
to memoize context value comes in handy to avoid re-rendering of all the context consumers
I believe that calling setCount will always rerender even if the same value is passed to the function.
But the line
const value = React.useMemo(() => [count, setCount], [count])
Will stop setCount being called unless there is a different value for the count. Thus reducing re-renders and increasing performance.
You can test this theory out by putting a log inside and seeing how the component renders with and without the useMemo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With