How to use Redux in Next.js
Tags: redux, nextjs, react, webdev
Published: 2022-07-29 18:38:00

**Written by [Mohammad Faisal](https://blog.logrocket.com/author/mohammadfaisal/)✏️**

[Redux](https://blog.logrocket.com/tag/redux/) is one of the most popular state management solutions in the React ecosystem. Nowadays, there are [plenty of alternatives](https://blog.logrocket.com/react-hooks-context-redux-state-management/), but Redux is still the most trusted and widely used tool. 

For this reason, many projects that use Next.js want to take advantage of Redux as well. But using Redux in a Next application has a few catches, and the setup is not always straightforward. That’s why this article will walk you through how we can set up a Next project with Redux.

### Contents

*   [Why should you use Redux with Next.js?](#why-should-use-redux-next-js)
*   [Building a sample app with Next.js and Redux](#building-sample-app-next-js-redux)
*   [Using the Redux store](#using-redux-store)
*   [Persisting the state in Next.js](#persisting-state-next-js)

## Why should you use Redux with Next.js? <a name="why-should-use-redux-next-js">

There are a lot of reasons why you might want to use Redux in a Next application. Let’s take a look at some of them.

### Sharing state <a name="sharing-state">

Usually, a central state is used to manage the shared data between the components in a tree. In React, data flows only downwards, which means you can pass data from the parent component to a child component. 

This limitation sometimes makes things hard, because the components might not be close in the component tree, and there might not even be a parent-child path. 

In this case, using a common store that wraps all the components makes total sense, and you might consider Redux.

### Redux is very powerful <a name="redux-very-powerful">

Redux is very powerful as a state management solution. It’s been around for a while, so it has excellent community support. 

If you are building something serious and unsure which use-cases might appear in the future, more likely than not, Redux will have a solution for you. While nothing is completely future-proof, Redux is a safe bet for long-term projects.

### Everybody knows Redux <a name="everyone-knows-redux">

In many projects, speed is often a priority. Many React developers are already familiar with Redux, and companies often want to use the same tool across all of the projects if possible. 

This means even if you are working in a company that is building a new project in Next, you might be forced to use Redux anyway, so it’s a good idea to learn how to use it based on popularity alone.

## Building a sample app with Next.js and Redux <a name="building-sample-app-next-js-redux">

Today we will build a simple application that tracks if a user is logged in or not, then based on the state, changes the text above the button. 

![Sample app login button](https://blog.logrocket.com/wp-content/uploads/2022/07/Sample-app-login-button.png) ![Sample app logout button](https://blog.logrocket.com/wp-content/uploads/2022/07/Sample-app-logout-button.png) 

The purpose of this project is to demonstrate how to use Redux, so I am keeping things simple here so that we can focus on the Redux integration with the Next. Going forward, we have two options. We can use plain [Redux](https://redux.js.org/), or we can use [Redux Toolkit](https://redux-toolkit.js.org/). 

Redux is being used in many legacy projects, but [Redux Toolkit](https://blog.logrocket.com/handling-user-authentication-redux-toolkit/) is recommended, as it reduces a lot of boilerplate code and has improved performance. However the setups are almost the same for both of these. 

Let's create the starter project by running the following command:

```shell
yarn create next-app --typescript
```

You can see the project in action by running `yarn dev` and visiting http://localhost:3000/ on your browser.

### Installing the dependencies <a name="installing-dependencies">

Let's install the required dependencies for Redux Toolkit:

```shell
yarn add @reduxjs/toolkit react-redux
```

As we are using Next, we will need an additional package to take care of our server-side rendering:

```shell
yarn add next-redux-wrapper
```

### Creating the slice <a name="creating-slice">

Let's create a new folder called `store` and create a file named `authSlice.ts` inside it. [The official documentation](https://redux.js.org/tutorials/essentials/part-2-app-structure) defines a slice as: “a collection of Redux reducer logic and actions for a single feature in your app.” 

We will put the logic for our `authState` inside of this `authSlice.ts` file:

```typescript
import { createSlice } from "@reduxjs/toolkit";
import { AppState } from "./store";
import { HYDRATE } from "next-redux-wrapper";

// Type for our state
export interface AuthState {
  authState: boolean;
}

// Initial state
const initialState: AuthState = {
  authState: false,
};

// Actual Slice
export const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {

    // Action to set the authentication status
    setAuthState(state, action) {
      state.authState = action.payload;
    },

    // Special reducer for hydrating the state. Special case for next-redux-wrapper
    extraReducers: {
      [HYDRATE]: (state, action) => {
        return {
          ...state,
          ...action.payload.auth,
        };
      },
    },

  },
});

export const { setAuthState } = authSlice.actions;

export const selectAuthState = (state: AppState) => state.auth.authState;

export default authSlice.reducer;
```

This is a straightforward slice. A slice for any normal React application using Redux will be just like this. There is nothing special for Next yet. 

The only thing we are doing here is defining the `authState` in our store and creating the action for setting the `authState` named `setAuthState`. 

In line 27, you will notice there is a special reducer that we are adding here called `HYDRATE`. The `HYDRATE` action handler must properly reconcile the hydrated state on top of the existing state (if any). 

Basically, when any page refresh occurs, if you navigate from one page to another page, or the `getStaticProps` or the `getServerSideProps` functions are called, a `HYDRATE` action will be dispatched at that moment. The `payload` of this action will contain the state at the moment of static generation or server-side rendering, so your reducer must merge it with the existing client state properly.

### Creating the store <a name="creating-store">

Next, create a file named `store.ts` to create the store, and add our `authSlice` there:

```typescript
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
import { authSlice } from "./authSlice";
import { createWrapper } from "next-redux-wrapper";

const makeStore = () =>
  configureStore({
    reducer: {
      [authSlice.name]: authSlice.reducer,
    },
    devTools: true,
  });

export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<AppStore["getState"]>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  AppState,
  unknown,
  Action
>;

export const wrapper = createWrapper<AppStore>(makeStore);
```

Notice on line 22 where we export a special `wrapper` function. This wrapper eliminates the need for a `Provider` that we would use in a normal React application.

### Updating the app <a name="updating-app">

We have to do one last thing to finish setting up our Redux architecture. Open the `_app.tsx` file and wrap our component like so:

```typescript
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { wrapper } from "../store/store";

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default wrapper.withRedux(MyApp);
```

Notice at line 9 that we are wrapping our component with `withRedux`. We can wrap the individual pages as well, but that is not recommended; when we navigate from one page to another, if that particular page is not wrapped, it will crash.

## Using the Redux store <a name="using-redux-store">

Our Redux setup is complete! Let’s use our Redux store inside the `index.tsx` page like so:

```typescript
import type { NextPage } from "next";
import { selectAuthState, setAuthState } from "../store/authSlice";
import { useDispatch, useSelector } from "react-redux";

const Home: NextPage = () => {
  const authState = useSelector(selectAuthState);
  const dispatch = useDispatch();
  return (
    <div>
      <div>{authState ? "Logged in" : "Not Logged In"}</div>
      <button
        onClick={() =>
          authState
            ? dispatch(setAuthState(false))
            : dispatch(setAuthState(true))
        }
      >
        {authState ? "Logout" : "LogIn"}
      </button>
    </div>
  );
};

export default Home;
```

Any Redux store has two main purposes: reading and updating. 

On line 6, you can see we are reading the state using the `useSelector` function provided by `react-redux`. 

We have a button where we can toggle the `authState`, and based on this, we are changing the text on the button.

## Persisting the state in Next.js <a name="persisting-state-next-js">

Now we have successfully set up our Redux store. You can verify it by clicking the button, which will dispatch actions based on the current state and update the store, which will eventually change the state. 

But if you refresh your page, you will see that the state doesn't persist. This is because in Next, each page is rendered on demand, which means when you navigate from one page to another, the previous state will be gone. 

For this case, if the user is logged in, then whenever you switch to another page, the user will be logged out automatically as the initial `authState` is defined as false. 

To resolve this issue, we will take advantage of the wrapper function that we created earlier and use Next's special function `getServerSideProps`, as this will get called each time the page loads. 

Let’s add the following code into our `index.tsx` file:

```typescript
export const getServerSideProps = wrapper.getServerSideProps(
  (store) =>
    async ({ params }) => {
      // we can set the initial state from here
      // we are setting to false but you can run your custom logic here
      await store.dispatch(setAuthState(false)); 
      console.log("State on server", store.getState());
      return {
        props: {
          authState: false,
        },
      };
    }
);
```

We are generating the initial state inside the `getServerSideProps` function here so even if you refresh the page you will see that the state values remain the same.

## Conclusion

That's how you can integrate Redux with a Next application! You can find the GitHub repository for this project [here](https://github.com/Mohammad-Faisal/nextjs-redux-integration). I would also encourage you to review the documentation of [next-redux-wrapper](https://github.com/kirill-konshin/next-redux-wrapper) to learn more about other use cases. 

Have a great day!

---

## [LogRocket](https://logrocket.com/signup): Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try [LogRocket](https://logrocket.com/signup). 

[![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://logrocket.com/signup)

[LogRocket](https://logrocket.com/signup) is like a DVR for web and mobile apps, recording literally everything that happens on your Next app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — [start monitoring for free](https://logrocket.com/signup).