Zustand: Stupid Simple State Management Tool!
Tags: react, webdev, beginners, tutorial
Published: 2022-02-25 14:56:38



Did you ever wanted to have a simple, easy, efficient and lovely state-management solution for your react projects ? then search no more because today i'll show you a pretty neat technology that includes all those attributes. Are you exited ? Let's get started!

## What is Zustand
from the creator of Zustand *pmndrs*:

> Zustand is a small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy api based on hooks, isn't boilerplatey or opinionated.

[Check out the repo to learn more](https://github.com/pmndrs/zustand)

You will see from the example below that Zustand is indeed a small, fast and scalable bearbones state-management solution.

## Why Zustand over Redux/Context-API ?

- Zustand is simple and not opinionated
- Doesn't wrap your app in a provider
- Utilizes hooks for handling state
- No configuration needed

## Basic usage

We will create a counter app as an example

- Install the dependency
`npm i zustand`
- Create a store
```javascript
// store/store.js

import create from 'zustand'

export const useStore = create(set => ({
 count: 0,
 incrementCount: () => set(state => ({count: state.count + 1})),
 incrementCount: () => set(state => ({count: state.count - 1}))	
}))
```

> Note
> `create` is a special function that creates a state object with the props we defined
> `set` is a special function that merges the state.

> The curly braces inside parenthesis `() => ({})` tells javascript that we are returning an object instead of it being a code block

- Use the hook inside your component
```JSX
import {useStore} from "./store/store.js"
function MyComponent() {
// you can destrcture the state
// const count = useStore({count} => count)
const count = useStore(state => state.count)
const incrementCount = useStore(state => state.decrementCount)
const incrementCount = useStore(state => state.decrementCount)

return 
	<div>
		<p>Count: {count}</p>
		<button onClick={() => incrementCount}>Increment</button>
		<button onClick={() => incrementCount}>Decrement</button>
	</div>
}
```

And voilà that's it! simple right ?

## Zustand Todo App

We will create the ole Todo app to demonstrate how it easy to work with Zustand

> The purpose of this article is just to show how to use Zustand so i'll keep the app simple and not include check, rename or delete functionality for the todos

- Open the terminal, Create a react app and navigate to it 
 `npx create-react-app zustand-example && cd zustand-example`

After the installation has been finished we will create a simple form with an input and submit button, So go ahead and type:

```JSX
import styles from "./App.module.css";
import {useState} from "react"

function App() {
  const handleSubmit = (e) => {
	e.preventDefault()
	}
  return (
    <div className={styles.App}>
      <form onSubmit={handleSubmit} className={styles.form}>
        <input value={value} onChange={(e) => setValue(e.currentTarget.value)} className={styles.input} placeholder="Add a new todo" />
        <button className={styles.button}>Add</button>
      </form>
    </div>
  );
}

export default App;

```


As you can see this is a generic form with a controlled input,  Here is how our form looks like:
!
![initial form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nn3mg82uegund23m9wop.png)

This is the styles if you're wondering
```css
.App {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: whitesmoke;
}

.form {
  width: 30%;
  height: 80%;
  background: white;
  border-radius: 12px;
  padding: 2rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-shadow: 0 0 5px black;
}

.input {
  width: 80%;
  padding: 10px 12px;
}

.button {
  color: white;
  background: aqua;
  padding: 10px 20px;
  margin: 20px 0;
  border: none;
  width: 140px;
}

```

We will now implement Zustand
- first install the dependency 
`npm i zustand` 
- inside the `src` folder create a folder `store` with `store.js` in it 

![store folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljyvc5ie8j8nftsibpd6.png)



Inside the store object we will create `todos`  property which is an array and `addTodo` method to push a new todo to the array

```JSX
import create from "zustand";

export const useStore = create((set) => ({
  todos: [],
  addTodo: (todo) =>
    set((state) => ({
      todos: [...state.todos, todo],
    })),
}));
```

We're pretty much done here, Now we need to add logic to our form

- Import `useStore` hook and call it 
```jsx
import {useStore} from "./store/store"

function App() {
  const todos = useStore((state) => state.todos);
  const addTodo = useStore((state) => state.addTodo);
}
```
- Inside `handleSubmit` function we will submit a new todo to our todos array
```jsx
const handleSubmit = (e) => {
	e.preventDefault()
	addTodo(value);
}
```

And finally we will map the `todos` array to represent the todos

```jsx
return (
{todos.map((todo) => {
  return (
    <ul>
     <li>{todo}</li>
    </ul>
  );
 })}
)
```

And that's it!, Lets test our app


![final form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxyj9n5rrfroemac9fp1.png)

Full code:
```jsx
import { useState } from "react";
import styles from "./App.module.css";
import { useStore } from "./store/store";
function App() {
  const todos = useStore((state) => state.todos);
  const addTodo = useStore((state) => state.addTodo);

  const [value, setValue] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    addTodo(value);
    setValue("");
  };
  return (
    <div className={styles.App}>
      <form onSubmit={handleSubmit} className={styles.form}>
        <input
          value={value}
          onChange={(e) => setValue(e.currentTarget.value)}
          className={styles.input}
          placeholder="Add a new todo"
        />
        <button className={styles.button}>Add</button>

        {todos.map((todo) => {
          return (
            <ul>
              <li>{todo}</li>
            </ul>
          );
        })}
      </form>
    </div>
  );
}

export default App;

```

## Typescript

If you're using typescript you can define the store types with `interface`

```javascript
import create from "zustand";

interface IStore {
	todos: string[];
	addTodo: (todo: string) => string
}

export const useStore = create<IStore>((set) => ({
  todos: [],
  addTodo: (todo) =>
    set((state) => ({
      todos: [...state.todos, todo],
    })),
}));

```

## Conclusion 

We've reached the end of this post hopefully it encourages you to use Zustand :). If you like this post you can follow me for more, Thanks for reading, Happy state-managing!

### Also chack out my other post: "useReducer vs useState"
{% embed https://dev.to/m0nm/usestate-vs-usereducer-what-are-they-and-when-to-use-them-2c5c %}

### Some tips on how to build a project
{% embed https://dev.to/m0nm/a-beginners-guide-on-how-to-build-projects-66d %}