DEV Community

Cover image for Day 12 of #100DaysOfCode — Understanding Zustand
M Saad Ahmad
M Saad Ahmad

Posted on

Day 12 of #100DaysOfCode — Understanding Zustand

Yesterday (Day 11) was all about understanding what state management actually is and why React apps eventually need something more powerful than just props and local state. So for Day 12 of my 100 Days of Code, the goal was to pick one state manager and start learning it hands-on. I chose Zustand, mainly because it’s lightweight, beginner-friendly, and doesn’t force you into a complex setup before you even write your first line of logic. And honestly… diving into it made state sharing between components feel way easier than I expected.


What is Zustand?

Zustand is a lightweight, minimal-boilerplate state management library for React. It lets you:

  • Share data between components without prop drilling
  • Avoid the complexity of heavy libraries
  • Skip the whole Context Provider wrapper situation

In Zustand, shared data lives inside something called a store, basically a container that holds your state and the functions (actions) that update that state. Think of it as a global object that any component can subscribe to.


Creating a Zustand Store

Here’s a simple example:

import { create } from 'zustand'

// Create a store
const useCountStore = create((set) => ({
  count: 0,  // initial state
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))
Enter fullscreen mode Exit fullscreen mode

Now you can use this store in any component without passing props around:

function Counter() {
  const count = useCountStore((state) => state.count)
  const increment = useCountStore((state) => state.increment)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+1</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

🤯 The Interesting Part: Using Only What You Need

With Zustand, you don’t need to pull in the entire state object every time.
If all you need is the increment function, you can select just that:

const increment = useCountStore((state) => state.increment)
Enter fullscreen mode Exit fullscreen mode

This works because:

  • Calling increment() updates the store.
  • Zustand notifies only the components that actually use the updated state.
  • The component doesn’t need count to perform the increment, only to display the result.

So if you only want to increment, you don’t have to subscribe to the count value at all.
If you want to see the updated value in real-time, then you subscribe to count too.

That’s what makes Zustand feel so clean and efficient.


🔄 Sharing State Between Components (Without Context API)

Here’s an example to show how two different components can work with shared state:

import { create } from 'zustand'

const useCountStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

function IncrementButton() {
  const increment = useCountStore((state) => state.increment)
  return <button onClick={increment}>Add 1</button>
}

function Display() {
  const count = useCountStore((state) => state.count)
  return <p>Count: {count}</p>
}

function App() {
  return (
    <div>
      <Display />
      <IncrementButton />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

What’s happening here?

  • useCountStore → creates shared state (count)
  • IncrementButton → pulls only the increment function
  • Display → pulls only the count value
  • Clicking the button updates the store, and Display automatically re-renders with the new value

No context providers, no prop drilling, Zustand handles the subscription logic internally.


“Wait a minute. Isn’t This Just a Custom Hook?”

This is where the magic clicks.

Yes, Zustand feels like a custom hook, but behaves very differently:

Custom Hooks

  • Create new copies of state for every component
  • State is not shared between components

Zustand

  • Creates one global store
  • All components share the same state
  • Works like Context API without needing a provider wrapper (same power, less hassle, better performance)

In simple words:
➡️ Zustand = global state
➡️ Custom hooks = local state per component


Final Thoughts

Wrapping up Day 12, diving into Zustand helped me see how straightforward global state management can be when the tool gets out of your way. It’s fast, minimal, and does exactly what you need without the usual boilerplate that comes with other solutions. That's the reason it is a go-to choice for so many React developers.

If you are looking into state managers and want something intuitive from the beginning, Zustand is certainly worth considering.

Happy coding!

Top comments (0)