AK

Ankur Kedia

Ankur

BlogProjects

Simplifying State Management with React Hooks using Zustand

Navigating basic state management with Hooks API feat. Zustand

27 May, 20214 min read
ZustandCredits: Zustand Examples

State management is probably one of the hardest parts of app development. More importantly, it is also the most crucial part to get right. This article is about simplifying the state management of your app with no new concepts. We will use Zustand to solve this which has hooks at its core. Covering the basics in this article, we will create a simple todo app. Since React Hooks are used to perform all the operations, basic hooks knowledge is all you'll need to sail through state management with Zustand.

What is Zustand?

Zustand is a simple, lightweight, fast, and React hooks based state management.

A small, fast and scaleable barebones state-management solution. Has a comfy API based on hooks, isn't boilerplate-y or opinionated, but still just enough to be explicit and flux-like.

Features

  • Lightweight.
  • Little(hooks) or no learning curve.
  • Makes hooks the primary means of consuming state.
  • Not opinionated.
  • Transient updates.

Apart from the convenience, Zustand solves some of the common problems with other libraries like complex flows, over-engineered solutions. It also solves some common documented issues with major existing libraries and patterns like the Context loss issue, React concurrency issues, Zombie child problem.

How to use it?

To demonstrate, we will create a basic todo app with CRUD operations. We will start with creating a store. Then, initialize an array of todos and add a function to add a todo to the list.

store.js
import create from 'zustand';
const useStore = create((set) => ({
todos: [],
add: (title) =>
set((state) => ({ todos: [...state.todos, { title }] }))
}));

Then, we attach the state todos we defined in the store to our components.

TodoList.js
import { useStore } from './store';
function TodoList() {
const todos = useStore((state) => state.todos);
return (
<div>
{todos.map(({ title }) => (
<div>{title}</div>
))}
</div>
);
}

Finally, we attach the add function which we defined to our button element. We will pass the input value as the title for the todo item.

TodoInput.js
import { useStore } from './store';
function TodoInput() {
const [inputValue, setInputValue] = React.useState('');
const add = useStore((state) => state.add);
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={() => add(inputValue)}> Add </button>
</div>
);
}

Et voila, we have a rudimentary version of the todo app working. The same patterns of get and set can be used across the app for all sorts of operations. We have also created the toggleDone and remove functions along the same line. Our store looks like the code below. For complete functionality, check the codesandbox link below.

store.js
import create from "zustand";
const useStore = create((set) => ({
todos: [],
add: (title) =>
set((state) => ({ todos: [...state.todos, { title }] })),
toggleDone: (index) =>
set((state) => ({
todos: state.todos.map((todo, id) => {
if (index !== id) {
return todo;
}
return { ...todo, done: !todo.done };
})
})),
remove: (index) =>
set((state) => ({
todos: state.todos.filter((todo, id) => id !== index)
}))
}));

Edit todo-zustand-react

Advanced features

For large projects, we need a lot more than just CRUD operations, but Zustand has got you covered there too. It already has support for the following:

  • Async operations: You just need to call set whenever you're ready, it doesn't matter if your actions are async or not.
  • Middlewares: Compose and pipe your middlewares any way you like.
  • Multiple stores fetching: You can create as many selectors as you like.
  • Devtools: Provides an in-built devtool middleware.
  • Usage with Redux: If you still want to use reducer and action pattern, you can follow it here too.
  • Handling nested states: Manipulating nested structures is tedious. You can use immer as a middleware though.

Disadvantages

Although Zustand's documentation is concise, has a good flow, and is very easy to understand, it could use some more detailing and example in some sections like handling multiple middlewares, managing nested states, code optimizations for better performance. So, please considering contributing to Zustand.

Caution: You Might Not Need Redux (or any other state management library)

Conclusion

Using Zustand is very convenient and you don't need a load of information to get started. When comparing with seasoned state management solutions, it definitely has an edge when it comes to DX. Its simplicity, flexibility, and unopinionated nature make it a compelling option. So, if you are a beginner in handling state management or if you have a project that does not deal with deeply nested structures, then Zustand might be a great fit for your project.

Hits 639

Discuss on Twitter

Share on