DEV Community

Sasith Warnaka
Sasith Warnaka

Posted on • Edited on

Redux with Persistent State Rehydration in Next.js (App Router)

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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,
});
Enter fullscreen mode Exit fullscreen mode

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',
});
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)