Zustand
Overview
While React Context is great for Dependency Injection, it lacks performance optimization (it re-renders all consumers on any change). Historically, developers used Redux for heavy global state, but Redux is notorious for massive boilerplate. Zustand (German for 'state') is a modern, blazing-fast, and minimalist state management library. It uses hooks, requires zero Providers, and solves the re-render problem natively.
Syntax
You define your state and your actions in one simple function. No reducers, no action types, no dispatchers required.
// store.js
import { create } from 'zustand';
// create() returns a custom hook
export const useBearStore = create((set) => ({
// State variables
bears: 0,
// Actions (Functions that modify the state)
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}));By passing a selector function to the hook (`state => state.bears`), Zustand automatically subscribes the component to *only* that specific slice of state. This is a massive performance upgrade over React Context.
import { useBearStore } from './store';
function BearCounter() {
// We can select ONLY the exact piece of state we need.
// This component will ONLY re-render if 'bears' changes.
const bears = useBearStore((state) => state.bears);
return <h1>{bears} around here ...</h1>;
}
function Controls() {
// We can extract just the actions.
// This component will NEVER re-render, because the action functions are stable!
const increasePopulation = useBearStore((state) => state.increasePopulation);
return <button onClick={increasePopulation}>Add Bear</button>;
}Common Pitfalls
- Forgetting to use selectors. If you just call `const state = useBearStore()`, the component will re-render whenever *anything* in the store changes, defeating Zustand's primary performance benefit.
Interview Tips
- If asked about Redux, mention that while Redux is still heavily used in enterprise legacy apps, the community is moving towards Zustand (for UI state) and React Query (for Server state) because they are much simpler and require less boilerplate.
Real-World Example
A Shopping Cart store that can be accessed anywhere without wrapping the app in a Provider.
export const useCartStore = create((set) => ({
items: [],
addItem: (product) => set((state) => {
// Check if item exists, update qty, or push new
const exists = state.items.find(i => i.id === product.id);
if (exists) {
return {
items: state.items.map(i => i.id === product.id ? {...i, qty: i.qty + 1} : i)
};
}
return { items: [...state.items, { ...product, qty: 1 }] };
}),
clearCart: () => set({ items: [] })
}));