Discover more from ByteBullet
#07: Current state of state management
What are current options for state management? Why would I need a state manager? What is relevant? What is maintained? Everything answered in this edition! 🔥
Hey everyone! In last week’s edition we took a look at my favorite API client side stack where I mentioned we could completely remove any state management libraries and rely only on cache in react-query. But one question still persists:
What if my app requires a global state?
Here is what's in store to answer the question above (text highlighted red is a link):
Why do I need a state manager?
Recoil - atomic approach, created by Facebook, simple
Redux - dispatch events which change state, a lot of boilerplate code
Zustand - supercharged useState
Hookstate - supercharged useState
Mobx - pure JS with adapters for react, state in classes
Effector - pure JS with adapters for react, create effects and dispatch them on stores
Valtio - wrap your initial state in a proxy and then directly modify it, resulting in change propagation
Why do I need a state manager?
Let’s take for example a simple todo list app. One might not need a state manager if the app only creates, displays, edits and deletes (CRUD) the entries with an API. Everything can be done with a simple
fetch and basic react constructs or to be future proof with react-query and it’s cache.
But imagine we want to add theme switching, complex notification system, undo/redo functionality or complete offline mode without an API. Each of these might require a global state depending on the use case and future plans with the app.
Adding global state is easy, reworking it is hard and removing it is fundamentally impossible.
I have worked on an app where Redux was used to only cache API calls and was intertwined with each aspect of the app. This would require a rewrite and refactor of each component in the app.
That is why I always use react-query as it satisfies 99% of all use cases. If it does not then I personally opt for context providers or atomic states (later on). But there are still use cases where robust global state managers are required. For example fully offline apps which do not sync with an API like an audio mixer, photo editor, simple note taking app, …
With everything out of my mind, let’s head straight into currently maintained and robust solutions for state management by implementing a simple counter app with each one of them.
Recoil is a simple but powerful tool made by Facebook which is the first on the list that utilizes the atomic approach to state management. You crate atoms (separate atomic state values) and then use hooks which work like
useSate, but propagate to each component that uses them.
Jotai also utilizes atomic approach. It is similar to Recoil but offers more functionality thanks to it’s built in utility features (storage, async, SSR, …) and integrations (tRPC, react-query, …) this means that you can have same developer facing interface for state management and API’s.
Redux was the go-to global state management library for a long time. But these days it requires more boiler plate code than others. It has reducers which are combined into one store. You dispatch actions, which are then caught by the reducers and they modify the state in the store accordingly.
They created redux-toolkit which mostly addresses the boilerplate problem, but still Redux requires quite a lot of setup in comparison to other libraries so I opted to link their example of a counter app implementation using redux-toolkit which will make more sense then me just showing here one component and an implementation of slice from redux-toolkit.
Zustand is the weird kid on the block, but in a good way. It works by creating a store which contains values and modification functions. Thus the data is fully encapsulated. This is good because you have a consistent interface and you are less likely to duplicate code.
Hookstate creates a state using the
hookstate function. This store can be manipulated directly from outside or using hooks from inside react components. That is pretty much it. I strongly suggest you to take a look at the examples they give on their web.
Mobx is also one of the older state managers. It is pure JS (can be used without react) and also has adapters for react. It utilizes JS classes which completely encapsulate the whole state. It is quite complex to show a fully self explanatory code example. Code is more than words. Go take a look at their website!
Effector works by calling events, which you define, that Stores subscribe to. It has pretty simple functional API even tho the description can be a bit intimidating.
Valtio is quite interesting as it utilizes a proxy around your initial state that can be modified directly. It is similar to the Zustand API but with one layer of abstraction removed. Each one has it’s use cases, so if you are deciding between these two, then I recommend to compare the docs directly.
What would you choose?
I would personally choose jotai as it offers both ease of use and extensibility via different integrations. What would you choose and why? Dm, mail or join my discord server, where we can chat directly!
It took me some time to gather this information and it would make my day, if you would join my newsletter! ♥️
ByteBullet is reader supported. Join other Software Engineers who receive this newsletter weekly each Saturday!