It can be overwhelming when it comes to application state management on the different pages when working with Next.js. Redux comes in handy in this case which is a robust and effective state management solution and it is made better when implemented with Redux Persist which makes the state to survive even after a page refresh. This tutorial is aimed a getting started with Redux and Redux Persist in Next.js, in particular with the App Router (/app) structure.
Prerequisites
Before starting, ensure that you have Node.js and npm installed. If not, download and install them from the official Node.js website.
Step 1: Setting up a Next.js App Router Project
To create a new Next.js project with the App Router structure, run the following command:
npx create-next-app@latest my-next-app
Make sure to enable the experimental App Router feature when prompted.
Step 2: Installing Redux and Redux Persist
Next, install the required packages for Redux and Redux Persist:
npm install redux react-redux redux-persist
These dependencies will help you manage state within your app and persist it across sessions.
Step 3: Setting Up Redux Store and Persist Configuration
In your project, create a redux folder in the src directory to organize Redux files. Inside this folder, create a store.js file to configure the Redux store and Redux Persist.
// src/redux/store.js
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import rootReducer from './reducers';
const persistConfig = {
key: 'root',
storage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
export const store = configureStore({
reducer: persistedReducer,
});
export const persistor = persistStore(store);
Step 4: Creating Reducers
In the same redux folder, create a reducers folder to define your reducers. For this example, create a simple counter reducer.
// src/redux/reducers/counterReducer.js
const initialState = {
count: 0,
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
export default counterReducer;
Next, create an index.js file in the reducers folder to combine reducers (if you have multiple):
// src/redux/reducers/index.js
import { combineReducers } from 'redux';
import counterReducer from './counterReducer';
export default combineReducers({
counter: counterReducer,
});
Step 5: Creating Actions
In the redux folder, create an actions folder to define action creators. Create a counterActions.js file to handle the counter actions.
// src/redux/actions/counterActions.js
export const increment = () => ({
type: 'INCREMENT',
});
export const decrement = () => ({
type: 'DECREMENT',
});
Step 6: Integrating Redux and Redux Persist with App Router
To integrate Redux and Redux Persist with the Next.js App Router, modify the layout.js file within the app directory. This file wraps your application’s UI and ensures that Redux and Redux Persist are accessible across all routes.
// app/layout.js
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from '../src/redux/store';
import './globals.css';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
{children}
</PersistGate>
</Provider>
</body>
</html>
);
}
This setup ensures that Redux and Redux Persist are initialized when the app loads.
Step 7: Using Redux in a Component
Now, let's create a page that uses the Redux state. Inside the app directory, create a new folder counter and add a page.js file to create a simple counter component.
// app/counter/page.js
'use client'; // Enable client-side rendering for this page
import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement } from '../../src/redux/actions/counterActions';
export default function CounterPage() {
const count = useSelector((state) => state.counter.count);
const dispatch = useDispatch();
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
}
The useSelector hook retrieves the current counter state, and useDispatch dispatches the increment and decrement actions.
Step 8: Running Your Application
Finally, start your Next.js application by running:
npm run dev
Visit http://localhost:3000/counter to see your counter page in action. The state will persist even after page reloads, thanks to Redux Persist.
Conclusion
You have successfully integrated Redux and Redux Persist into a Next.js project using the App Router. This setup allows for seamless state management with persistence across sessions. From here, you can expand this approach to manage more complex states and interactions in your application. Happy coding!
Top comments (0)