How to Configure Redux Toolkit with NextJS using Typescript?

khizerrehandev
5 min readFeb 23, 2024

--

Here are easy steps you can configure redux toolkit to Next.js application.

I have already provided Code Sandbox to configure basic Redux Store using RTK using Stackblitz. You can get the link embedded link at the bottom of this article.

This Configurations works with NextJS with version 13.x.x. You can find complete code below in case you are interested to get code from a Github Repo.

Create a new project for Next.js using create-next-app command-line tool.

npx create-next-app@latest

What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*

Install Dependencies

npm install @reduxjs/toolkit react-redux

Once Initial project is setup is created you can configure Redux store for Next.js application.

🀷 How to Configure store ?

  • Create a folder called redux or store or redux. I have created store/ folder/
  • Create a file called store.ts
import { configureStore } from '@reduxjs/toolkit'

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

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

πŸ’‘ This code creates a Redux store, and also automatically configure the Redux DevTools extension so that you can inspect the store while developing.

Configure Typed hooks for (useDispatch, useSelector)

import { useDispatch, useSelector } from 'react-redux';
import type { TypedUseSelectorHook } from 'react-redux';
import { AppDispatch, RootState } from './store';

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

πŸ’‘ Defining Typed Hooks have benefits when you need to use useSelector, useDispatch in component.In order to know pros for having a seperate file you can know the reasons.

https://redux-toolkit.js.org/tutorials/typescript#define-typed-hooks

🀷 How to Configure feature slice?

There can be multiple features with an App or within same feature. Let me give you an example other then what i have shown in code below. Think of garments store where you can buy garments. We can have many feature slices:

  • Authentication Slice
  • User Profile Slice
  • Search Slices
  • Filters Slices
  • Cart Slice
  • Wishlist Slice
  • Product Catalog Slice

Similarly we can have many slices within an application and for that reason i have taken a basic example where i have created Counter slice. Which increments by +1 / Increment by +10 and decrement by -1.

  • Initial State for Counter Slice.
  • Associated Actions for that Slice inside the Reducer.
import { createSlice } from '@reduxjs/toolkit'

const initialState = {
value: 0,
}

export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {

state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})

// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer // EXPORT Slice reducer

πŸ’‘ Note: In Redux Toolkit, createSlice generates both action creators and reducers for you within a slice. However, if you want to create individual action creators separately from a slice, you can use createAction

🀷 How to Connect feature slice with store?

export const store = configureStore({
reducer: {
counter: CounterSlice, // Connecting default exported Slice reducertyept
},
});

πŸ“Œ Important Step:

🀷 How to Configure custom provider?

This is a crucial step as in order to wrap your Next.js Application with store so that component access store Root Layout needs to be wrapped with custom provider which can pass store to all children components.

'use client'; // πŸ”΄ Read Quote below

import { Provider } from 'react-redux';
import { store } from './store';

export function Providers({ children }: { children: React.ReactNode }) {
return <Provider store={store}>{children}</Provider>;
}

export default Providers;

πŸ’‘ Note: β€œuse client” is very Important to add to let NextJS know that this functional component will be treated as Client Component Rather than Server Component. Otherwise it will throw runtime exception in case you configured your custom provider with RootLayout component

🚨 Unhandled Runtime Error

πŸ”΄ Error: This function is not supported in React Server Components. Please only use this export in a Client Component.

Wrap your RootLayout file with custom provider:

By Wrapping Root Layout File with custom provider children of layout.jsx will have an access for Redux store. So once it is configured client component can access store using hooks defined in Typed hooks file.


// layout.tsx Initial Template ℹ️
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}


// layout.tsx After You configure Provider βœ…

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<Providers>{children}</Providers>
</body>
</html>
);

🀷 How to access configured store within a component using typed hooks?


'use client'; // πŸ”΄ IMPORTANT!!

import { useAppDispatch, useAppSelector } from './store';
import { decrement, increment, incrementByAmount } from './store/slices/counter';

export default function Home() {
const counter = useAppSelector((state) => state.counter.value); // Return Root State Slices
const dispatch = useAppDispatch(); // Action Dispatcher

return (
<main className="flex min-h-screen flex-col items-center justify-center p-24">
<div className="text-center mb-12">Count is {counter}</div>

<div className="flex">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
onClick={() => {
dispatch(increment());
}}
>
Increment
</button>
<button
className="ml-2 bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
onClick={() => {
dispatch(decrement());
}}
>
Decrement
</button>

<button
className="ml-2 bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
onClick={() => {
dispatch(incrementByAmount(10));
}}
>
Incement By 10
</button>
</div>
</main>
);
}

Here’s the complete counter application as a running Code Sandbox:

Conclusion

This blog guides you step by step through configuring your Next.js application to connect with a Redux store using the Redux Toolkit library. If you found this article helpful or learned something new, I would greatly appreciate a round of applause πŸ‘ to provide more motivation. It only takes a few seconds.

Keep Supporting and Keep Learning. πŸ™

You can support me by buying coffee. β˜•

Thank you :)

--

--

khizerrehandev
khizerrehandev

Responses (2)