State management has always been opinionated in React community. Redux was a revolutionary tech for the React ecosystem when it was first released. It allowed applications to have a global store that was immutable and solved challenges like prop drilling elegantly. To this day, it continues to be great and scalable.
I've used redux and similar solutions for years and one thing that always bothered me was the amount of boilerplate required to get started with it. Redux toolkit largely solves the boilerplate issue but when compared to excellent solutions like MobX, MST it still seemed verbose for small to medium size projects.
A couple of weeks ago I wanted to refactor a decent sized write-heavy context state to a better solution, and naturally Redux, MobX came to mind. However, I wanted something simpler and more elegant.
Zustand to the rescue!!
As stated in the docs, "Zustand is a small, fast and scaleable barebones state-management solution. Has a comfy api based on hooks, isn't boilerplatey or opinionated, but still just enough to be explicit and flux-like".
What really motivated me to use Zustand was how simple it was to get started with it and great features like transient updates for often occurring state changes, memorized selectors, integration with immer! and the best no Providers!!
Let's go over a basic store example with Zustand using Typescript.
Install zustand
yarn add zustand
Creating a store
import create, { SetState, GetState } from 'zustand';
type CountStore {
count: number;
increment: () => void;
};
const useCountStore = create<CountStore>((set: SetState<CountStore>, get: GetState<CountStore>) => ({
count: 0,
increment: (): void => {
const { count } = get();
set({ count: count + 1 });
}
});
create
gives two arguments set
and get
. The set
function (you guessed it right!) merges the state, similar to setState
in class-based react components. And through the get
function we can access the current state of the store, especially helps when we want to access the state within an action. Quite useful!
Usage with components
Now, let's see how we can make use of our store in a component using hooks!
function Counter(): React.ReactElement {
const count = useCountStore(state => state.count);
const increment = useCountStore(state => state.increment);
return (
<div>
<h1>count: {count}</h1>
<button onClick={increment}>+1</button>
</div>
);
}
The store itself acts as a selector hook! Neat. We can also do multiple selects for the same.
const [count, increment] = useCountStore(state => [state.counter, state.increment]);
And that's it, we now have a simple store without any extra boilerplate code.
We haven't even scratched the surface with zustand yet. There are tons of amazing features like transient updates, immer integration, memorized selectors, async actions, middleware...and the list goes on. I feel they are better explained in the docs
Hopefully, this article helps as a brief introduction to Zustand. So far I am really enjoying using it.
Are you using Zustand already? Or want to talk all things javascript with me? Find me on twitter @karan_6864
Top comments (7)
Thanks for sharing!
The transient update feature looks pretty cool too, might give it a go in the next side project!
awesome!
How to combine stores in Zustand?
It's impressive how you could showcase the gist of Zustand in a concise article like this. This is my first time looking at Zustand, and it makes a lot of sense.
Glad to hear you liked it, thanks!
How to toggle boolean in zustand ?
Set the value to the opposite of its current. e.g. : flag: !flag
That will toggle it without having to explicitly pass the Boolean value.