When to use Zustand and React Context

React Context was never meant to be your application's state manager. There, I said it.
In 2018, Facebook introduced React Context. While it was intended to solve the "Prop Drilling" problem, it inadvertently popularized a new issue: Excessive Re-rendering.
To be fair, Context didn’t "introduce" re-renders—it just made them much easier to trigger accidentally.
React treats every function in your code as a node, as a part of a big graph (tree), which they call it as "Component Tree".
So, when a component sitting at a significantly top-level node changes its properties, React revisits every child of this node. It runs its functions and performs a "diffing" algorithm to see what needs to change in the actual DOM.
Even if the diffing algorithm finds that a child node doesn't need a DOM update, the "damage" (the execution of the function and the reconciliation logic) has already happened. This is fine for small apps, but for complex ones, it's a performance issue.
This is a core React problem. Context did nothing to solve this problem. It just made it easier to make these mistakes.
For example:
1) let us say, you have multiple properties (Eg: user, theme, notifications) in the context object, and a component is consuming only the "theme", , it will re-render every time any property in that object changes (Granularity).
2) There is no way you can stop this re-render for a component that does not need the re-render. Even using React.memo() doesn't work here. React intentionally bypassess memo if the component is consuming Context. React forces that component to re-render regardless of whether it’s memoized.
If you think of the problem intuitively for a minute, that the problem exists in React's nature, and the solution would naturally exist somewhere outside of this.
That is exactly where and how these state management solutions function.
Modern state management libraries such as Zustand, operate using a React 18 feature as its backbone - useSyncExternalStore().
Unlike React Context, when using these libraries, your state lives totally outside the component tree, as a plain JavaScript object. This is what usually gets called as "External Store".
This is created right when your JS bundle loads in the browser.
Any changes to the state are first written to this external store. This store holds the state and any functions that are used to update it.
When a function/component updates a piece of state, the store calculates the difference and updates it. So, what is the difference here? It is doing the same thing that react is doing it, right?
We can say yes. But, the difference is, these calculations are done outside of react without react ever noticing it.
When any part of this store changes, Zustand runs every selector in the app. These selectors are the things that enable granularity in Zustand. The selector runs and gets the current value of the the prop it is listening to, compares this new result with the previous result. If there is no difference, nothing happens. If it notices a difference, Zustand triggers a re-render for that specific component.
And, to be frank, these calculations performed by zustand are less expensive as well. Because, it is just a "===" check. Whereas, in react context, the comparisons are made for the entire components.
So, that is about all the internal architectural comparison. Now, let us get to the point. When to use what?
Since, we only have 2 contestants here, i.e., React Context and Zustand. There is actually a metric we can use to decide the usage part.
That metric is "Frequency".
Whenever you are taking a decision, the key thing to think about is, how often the components state will be updated. This can be termed as frequency.
If the state gets updated more frequently, go for an external state management library like Zustand.
If it's less, you can use React Context.
Example Scenarios
For data such as, auth states, use React Context. Because, the probability of auth state changing is very low. Use React Context for such scenarios where data rarely changes.
But, let us say, you are building filter components in your application, it is far better to use Zustand. Because, the probability that the user plays around with multiple filter combinations is very high compared to data such as auth states.
Hope you learned something from this.
Thanks for reading!!
Inspired by TkDodo.
0
7
0