Skip to main content

Command Palette

Search for a command to run...

How to Manage Global State in Next.js Using Redux Toolkit

Updated
4 min readView as Markdown
How to Manage Global State in Next.js Using Redux Toolkit
S

Full-stack developer with a passion for building scalable web applications using Next.js, TypeScript, and modern technologies. Experienced in ServiceNow development and scripting. Sharing knowledge and insights on web development and programming.

Managing global state in a Next.js application can be tricky, but Redux Toolkit (RTK) makes it easier by reducing boilerplate and improving performance. In this guide, we’ll walk through integrating Redux Toolkit with Next.js to efficiently manage application state.


Why Use Redux Toolkit in Next.js?

Next.js is a powerful React framework with built-in features like SSR (Server-Side Rendering) and SSG (Static Site Generation). However, it doesn’t provide a built-in solution for global state management. That’s where Redux Toolkit comes in.

Benefits of Redux Toolkit:

  • Less Boilerplate: Simplifies state management with built-in utilities.

  • Efficient Performance: Uses Immer for immutable updates and Redux Thunk for async actions.

  • Better Developer Experience: Includes built-in middleware and debugging tools.


Setting Up Redux Toolkit in Next.js

Step 1: Install Dependencies

Run the following command in your Next.js project:

npm install @reduxjs/toolkit react-redux

Step 2: Create a Redux Store

Inside your project, create a folder store and add a file called store.ts:

// store/store.ts
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './slices/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

Step 3: Create a Slice

Inside the store folder, create a slices directory and add counterSlice.ts:

// store/slices/counterSlice.ts
import { createSlice } from '@reduxjs/toolkit';

const initialState = { value: 0 };

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
});

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

Step 4: Provide the Store to Next.js

Next.js doesn’t have a built-in provider for Redux, so we wrap our app with the Redux Provider.

Modify pages/_app.tsx:

// pages/_app.tsx
import { Provider } from 'react-redux';
import { store } from '../store/store';
import type { AppProps } from 'next/app';

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

export default MyApp;

Step 5: Use Redux State in Components

Now, let’s use Redux state in a component.

Create components/Counter.tsx:

// components/Counter.tsx
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../store/store';
import { increment, decrement } from '../store/slices/counterSlice';

export default function Counter() {
  const count = useSelector((state: RootState) => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Counter: {count}</h1>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  );
}

Step 6: Add Counter to a Page

Modify pages/index.tsx:

// pages/index.tsx
import Counter from '../components/Counter';

export default function Home() {
  return (
    <div>
      <h1>Welcome to Redux Toolkit in Next.js</h1>
      <Counter />
    </div>
  );
}

Using Redux Toolkit with the Next.js App Router

If you’re using the App Router (app directory) in Next.js, the setup is slightly different. Instead of wrapping _app.tsx, you’ll use a provider in layout.tsx.

Step 1: Modify store.ts (Same as Above)

Step 2: Provide Store in layout.tsx

Modify app/layout.tsx:

// app/layout.tsx
import { Provider } from 'react-redux';
import { store } from '../store/store';
import type { ReactNode } from 'react';

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Provider store={store}>{children}</Provider>
      </body>
    </html>
  );
}

Use ‘use client’, if This function is not supported in React Server Components. Please only use this export in a Client Component.

Step 3: Use Redux in a Server Component

In the App Router, Redux is primarily used in Client Components. Mark components as 'use client' at the top.

Modify app/components/Counter.tsx:

// app/components/Counter.tsx
'use client';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../store/store';
import { increment, decrement } from '../store/slices/counterSlice';

export default function Counter() {
  const count = useSelector((state: RootState) => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Counter: {count}</h1>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  );
}

Step 4: Add Counter to a Page

Modify app/page.tsx:

// app/page.tsx
import Counter from './components/Counter';

export default function Home() {
  return (
    <div>
      <h1>Welcome to Redux Toolkit in Next.js (App Router)</h1>
      <Counter />
    </div>
  );
}

Conclusion

Redux Toolkit makes state management in Next.js simple and efficient. Whether you use the Pages Router or the App Router, the integration process is straightforward.

Next Steps:

  • Explore Redux Persist to save state between page reloads.

  • Use RTK Query for fetching and caching data.

  • Implement middleware for advanced state management.