Zustand uses a single function to create a store and returns a React hook, simplifying the API significantly.
// store/useCounterStore.js
import { create } from 'zustand';
// Define the state structure and actions interface
type CounterState = {
count: number;
inc: (by: number) => void;
dec: (by: number) => void;
};
// Create the store
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
// Actions use the 'set' function to update state
inc: (by) => set((state) => ({ count: state.count + by })),
dec: (by) => set((state) => ({ count: state.count - by })),
}));
// Component Usage
// components/Counter.jsx
import { useCounterStore } from './store/useCounterStore';
function Counter() {
// Select only the parts of the state you need.
// Zustand automatically optimizes re-renders.
const { count, inc, dec } = useCounterStore((s) => ({
count: s.count,
inc: s.inc,
dec: s.dec,
}));
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => inc(1)}>Increment</button>
<button onClick={() => dec(1)}>Decrement</button>
</div>
);
}Redux Toolkit uses slices to define state, reducers, and actions together, dramatically reducing Redux's traditional boilerplate but maintaining a strict architecture.
// store/counterSlice.js
import { createSlice, configureStore } from '@reduxjs/toolkit';
import { useDispatch, useSelector } from 'react-redux';
// 1. Define the Slice: State, Reducers, and Actions
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
// Redux Toolkit allows "mutating" logic inside reducers
// because it uses Immer library under the hood.
increment: (state, action) => {
state.value += action.payload || 1;
},
decrement: (state, action) => {
state.value -= action.payload || 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
// 2. Configure the Store
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
// RootState and AppDispatch types for TypeScript (professional practice)
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// Component Usage
// components/Counter.jsx
// (Requires <Provider store={store}> wrapper at the app root)
function Counter() {
const count = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch<AppDispatch>();
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => dispatch(increment(1))}>Increment</button>
<button onClick={() => dispatch(decrement(1))}>Decrement</button>
</div>
);
}🐻 Zustand vs. 🔴 Redux Toolkit (RTK) Comparison (2026)
The most significant modern advantage of Redux is its RTK Query utility, which is a state-of-the-art solution for server-state management. If you need powerful, built-in data fetching, RTK is often the winner. Otherwise, for pure client state, Zustand's simplicity is hard to beat.
