Managing React State Globally With Zustand

Goodluck Woha
4 min readDec 13, 2022

--

State management is sometimes considered the heart or engine of a React application. I mean, if there are no changes to state, then it’s not really an application, is it? Among all the different native hooks and third-party libraries we got blessed with for state management is one of my favourite libraries called Zustand.

Zustand is a unidirectional state manager capable of storing multiple and nested states in a single component (A.K.A Store). As a result, state in Zustand can easily be used across different React components without unnecessary prop drilling.

One of the things this state manager gets praised for more than anything is its simplicity and code conciseness. An advantage it has over its counterpart, Redux.

This article teaches you all about how to manage and render state with Zustand. It also covers Zustand’s native store for keeping custom hooks.

Store

Zustand allows you to create custom hooks for strings, numbers, booleans, arrays, and even functions. All of these hooks get saved into a store on Zustand. Well, you can’t use what you haven’t created can you? so you’ll have to import the create function from Zustand. With this function, you can create a new store and in that store have custom hooks containing the initial values of your state.

import create from "zustand";
const myStore = create(() => ({
number: 0,
}));

Managing State

With all your state saved into the store, you can take it a step further by creating functions which can be used to change the state of your initial custom hook. This can be done in two ways, the first is by calling the setState function of Zustand:

const myStore = create(() => ({
number: 0,
increment: () => myStore.setState((state) => ({ number: state.number + 1 })),
decrement: () => myStore.setState((state) => ({ number: state.number - 1 })),
reset: () => myStore.setState((state) => ({ number: (state.number = 0) })),
}));

And the second is by using this shorthand:

const myStore = create((set) = > ({
number: 0,
increment: set(state => ({number: state.number + 1})),
decrement: set(state => ({number: state.number - 1})),
reset: set(state => ({number: state.number = 0})),
}));

Using hooks connected to the setState function enables you to directly change the state of other custom hooks.

Slices

If your store starts getting verbose and harder to read, you can slice it into micro components and reuse them in the main store with a spread operator. You know? Those 3 dots that destructures values from components. With spread operators you can turn this:

const myStore = create((set, get) => ({
number: 0,
increment: () => set((state) => ({ number: state.number + 1 })),
decrement: () => set((state) => ({ number: state.number - 1 })),
reset: () => set((state) => ({ number: (state.number = 0) })),
results: [],
saveResult: () =>
set((state) => ({ results: [get().results, state.number] })),
}));

Into this:

const myStore = create((set, get) => ({
...calc(set),
...resultSheet(set, get),
}));

With a component for each ofcourse:

const calc = (set) => ({
number: 0,
increment: () => set((state) => ({ number: state.number + 1 })),
decrement: () => set((state) => ({ number: state.number - 1 })),
reset: () => set((state) => ({ number: (state.number = 0) })),
});
const resultSheet = (set, get) => ({
results: [],
saveResult: () =>
set((state) => ({ results: [get().results, state.number] })),
});

You must have noticed the get() keyword used as the second parameter in the myStore component. It can be called anything but as long as it is at the second parameter position, it becomes a shorthand for one of Zustand’s functions called getState which is in charge of fetching values within the store and passing them to other hooks in the store.

Rendering State

With a new store created, you can render your state anywhere in your React application by importing the created store and grabbing all the custom hooks you want your component to have access to:

import myStore from "./store/myStore";
const Calculator = () => {
const { number, increment, decrement, reset, saveResult, results } =
myStore();
return (
<>
<div>{number}</div>
<span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</span>
<div>
<button onClick={reset}>RESET</button>
</div>
<button onClick={saveResult}>SAVE</button>
<h5>
Results:
{results}
</h5>
</>
);
};
export default Calculator;

You can also grab specific custom hooks with a selector like so:

const number = myStore((state) => state.number);

Getting Started with Zustand

It is important to note that Zustand isn’t necessarily a replacement for hooks like useState. It is a state management system that should be used as an add-on for existing hooks to have a better organized store for states and custom hooks.

To install Zustand into your workspace, run the npm command:

npm install zustand

Or the yarn command:

yarn add zustand

Is it better than Redux?

Well, it depends. While Redux can be excessively verbose at times, it does help to scale an extremely large and complex React application. Zustand isn’t quite there yet and is mostly used for mid-size applications.

--

--