Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
State management remains a crucial aspect of building complex web applications, especially in modern Next.js projects (version 14 and newer). Let’s explore three popular state management libraries – Redux, Zustand, and Jotai – and compare their strengths, weaknesses, and use cases in the context of the latest Next.js applications.
Redux continues to be a powerful state management library, now with improved integration for Next.js 14+ projects.
Predictable state updatesPowerful debugging toolsLarge ecosystem and community supportMiddleware support for side effectsOfficial Next.js integration
Steeper learning curveMore boilerplate compared to alternativesCan be overkill for smaller applications
First, install the necessary packages:
npm install @reduxjs/toolkit react-redux next-redux-wrapper
Create a store:
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
export const makeStore = () =>
configureStore({
reducer: {
counter: counterReducer,
},
});
export type AppStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<AppStore['getState']>;
export type AppDispatch = AppStore['dispatch'];
Create a slice:
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface CounterState {
value: number;
}
const initialState: CounterState = {
value: 0,
};
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
Set up the provider:
'use client';
import { Provider } from 'react-redux';
import { makeStore } from '../store/store';
export function Providers({ children }: { children: React.ReactNode }) {
return <Provider store={makeStore()}>{children}</Provider>;
}
Wrap your app with the Redux provider:
import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
Use Redux in a client component:
'use client';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../../store/store';
import { increment, decrement } from '../../store/counterSlice';
export default function Counter() {
const count = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
}
Zustand remains an excellent choice for Next.js 14+ projects, offering simplicity and great performance.
Minimal boilerplateEasy to learn and useTypeScript support out of the boxExcellent performanceWorks well with React Server Components
Less ecosystem support compared to ReduxFewer built-in features for complex scenarios
Install Zustand:
npm install zustand
Create a store:
import { create } from 'zustand';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
}
export const useStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
Use Zustand in a client component:
'use client';
import { useStore } from '../../store/useStore';
export default function Counter() {
const { count, increment, decrement } = useStore();
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
Jotai’s atomic approach to state management works seamlessly with Next.js 14+ and its server components.
Atomic state managementMinimal boilerplateGreat for code splitting and lazy loadingExcellent TypeScript supportWorks well with React Server Components
Relatively new, smaller communityMay require a mental shift for developers used to traditional state management
Install Jotai:
npm install jotai
Create atoms:
import { atom } from 'jotai';
export const countAtom = atom(0);
Use Jotai in a client component:
'use client';
import { useAtom } from 'jotai';
import { countAtom } from '../../store/atoms';
export default function Counter() {
const [count, setCount] = useAtom(countAtom);
const increment = () => setCount((c) => c + 1);
const decrement = () => setCount((c) => c - 1);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
When deciding between Redux, Zustand, and Jotai for your modern Next.js project, consider these factors:
Each state management solution has its place in the Next.js 14+ ecosystem. Redux offers a robust approach with a large ecosystem. Zustand provides simplicity and performance with minimal boilerplate. Jotai introduces an atomic approach that’s great for code splitting and works well with server components.Choose the solution that best fits your project requirements, team expertise, and the specific needs of your Next.js 14+ application.