Implementing Zustand: A More Streamlined Approach to State Management
Zustand (German for "state") is a popular state management library created by Daishi Kato. It offers a more streamlined approach compared to Redux, while following the same unidirectional model for managing state.
For this exercise, we'll use Zustand to manage our application state. To get started, copy the 03-cart-context-with-initial-state
directory and to a new 07-complete-zustand
directory.
My recommendation is to use two different stores for managing the state.
Specifically, we'll use two different Zustand state hooks: one for managing the cart and another for reviews.
Challenge
After installing zustand
, you'll need to remove the existing CartContext
and ReviewContext
objects and replace them each with their own Zustand store.
In case you aren't familiar with Zustand, here's a quick overview of how it works.
WARNING You cannot safely use Zustand hooks that are declared globally!
Zustand hooks are normally global, but you can also create a Zustand hook and pass it around in a context, like so:
"use client";
import { useState, createContext, useContext } from "react";
import { create } from "zustand";
const createStore = (count: number) =>
create<{
count: number;
setCount: (cart: number) => void;
}>((set) => ({
count,
setCount(count: number) {
set({ count });
},
}));
const CountContext = createContext<ReturnType<typeof createStore> | null>(null);
export const useCount = () => {
if (!CartContext)
throw new Error("useCount must be used within a CountProvider");
return useContext(CountContext)!;
};
const CountProvider = ({
count,
children,
}: {
count: number;
children: React.ReactNode;
}) => {
const [store] = useState(() => createStore(count));
return (
<CountContext.Provider value={store}>{children}</CountContext.Provider>
);
};
export default CountProvider;
In order to get the Zustand hook in a Client Component, follow this pattern:
const useCountHook = useCount();
From there you can call the hook like this:
const { count, setCount } = useCountHook();
The above could also be shortened to:
const { count, setCount } = useCount()(); // remove "Hook" and add another "()"
Zustand also allows you to use selectors like so:
const count = useCount()((state) => state.count);
The above will force a re-render only when the returned value from the selector changes.