I've been looking into Zustand and Recoil -- two state management libraries that are relatively new.
Recoil is heavily advertised as being "very performant" for React apps with deeply-nested structures. However, I don't see how (or how exactly) it can be superior to Zustand performance-wise (concurrent mode aside).
I could've gotten it wrong, but here's how I understood it from articles and talks: The main reason "why" Recoil is performant is that any updates you make only trigger the relevant components to re-render, without bothering any other components. Recoil allows for it by design and out of the box, whereas Context-based libraries have to pass every change through the whole tree, have those changes diff'ed/reconciled and then probably only re-render what has to be changed.
Now, Zustand does not use the Context API at all. So, I would assume that (concurrent mode aside), it would have comparable performance benefits as Recoil, where Zustand would only "touch" the relevant components without ever piping the changes through the whole component tree.
Please let me know if I'm off in my understanding. Are these two libraries comparable in performance (without concurrent mode)? Or is there some other inherent property of Recoil's paradigm with atoms which makes it theoretically superior in terms of performance?
Please note: I would like the answer NOT to be influenced by patterns and practices too much. I understand that sometimes the biggest benefit of a paradigm can be in the "sound patterns it enforces", but I'm interested not in what they enforce but in what they allow to do with comparable effort. For example, I understand that a flat, normalized state will allow for better performance in Zustand, and that Zustand does not necessarily "force you to do it in a proper/scalable way". But I wouldn't want the "optionality" of the right patterns to be a disadvantage.
It is correct that both Recoil and Zustand aim to improve performance by limiting the number of components that need to re-render when the state changes. In this sense, they are comparable in performance.
The main difference between the two is in their implementation and approach to state management. Recoil uses a graph-based model, where each piece of state is represented by an atom and components can subscribe to specific atoms to receive updates. This allows for precise control over which components should re-render in response to state changes.
Zustand, on the other hand, uses a more traditional store and subscription model, similar to Redux. It allows you to create a store containing your application's state, and components can subscribe to the store to receive updates.
Both libraries can be performant, but it ultimately depends on how you use them and how you structure your state. For example, using a normalized, flat state in Zustand can help to minimize unnecessary re-renders, as can using Recoil's selector functions to select specific pieces of state.
In terms of inherent performance advantages, it's difficult to say without more context. In general, both libraries can be performant when used correctly, but it ultimately depends on the specific needs and requirements of your application.