How to use NextJs 13 with Redux Toolkit and Typescript
Tags: nextjs, redux, typescript, react
Published: 2023-09-15 18:49:02

## Intro

NextJs 13 was released with some game-changing features like server-side components, a router, improved TS support, and more. So this might require a few changes in how we write our code especially when using client libraries like Redux.

Here is a quick and simple guide to get started with Nextjs 13 and Redux.

## Get Started
Create a NextJs 13 application:
``` batch
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? **@/**

Then we install the Redux toolkit and React Redux
``` batch
npm i @reduxjs/toolkit react-redux
```

## Folder Structure
Normally Redux app would include an _app_ folder with a sub-folder called _features_. Instead, we are going to create a _redux_ folder and inside a _features_ folder

Inside the redux folder create a store.ts.

``` typescript
import { configureStore } from "@reduxjs/toolkit";
export const store = configureStore({
  reducer: {},
});
```

Should look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qpt22dbngykvrbaado7n.png)

## Slices
Inside the features folder, we will be saving our redux slices.

Inside the features folder, we will add a _todo-slice.ts_ file:
``` typescript
import { createSlice } from "@reduxjs/toolkit";

type Todo = {
  id: number;
  name: string;
  done: boolean;
};

type TodoState = {
  list: Todo[];
  user: string;
};

const initialState: TodoState = {
  list: [],
  user: "todo",
};

export const todo = createSlice({
  name: "todo",
  initialState,
  reducers: {
    addTodo: (state, action) => {
      state.list.push(action.payload);
    },
    removeTodo: (state, action) => {
      state.list = state.list.filter((todo) => todo.id !== action.payload);
    },
    toggleTodo: (state, action) => {
      const todo = state.list.find((todo) => todo.id === action.payload);
      if (todo) {
        todo.done = !todo.done;
      }
    },
  },
});

export const { addTodo, removeTodo, toggleTodo } = todo.actions;
export default todo.reducer;

```

## Store update
Now we need to update the store.ts file to add the reducer and add the RootState and our AddDispatch types to our TS types are always up to date with our slices.
```typescript
import { configureStore } from "@reduxjs/toolkit";
import todoReducer from "./features/todo-slice";

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

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

## Redux Provider
We need to create the redux provider now, so let's create a provider.tsx inside the redux folder. On top of the file make sure to add the `'use client'` string to tell NextJs this is a client component since all components are server components by default.
``` typescript
"use client";
import React from "react";
import { Provider } from "react-redux";
import { store } from "./store";

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

export default ReduxProvider;
```

Now we need to wrap our provider around our whole app. To do so we will need to change our root layout.tsx file to this. 

```react
import ReduxProvider from "@/redux/provider";
import "./globals.css";

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


```

## Use Redux 
Now let's create a client component that read from the redux store and dispatch events:
```typescript
"use client";

import { addTodo, removeTodo, toggleTodo } from "@/redux/features/todo-slice";
import { AppDispatch, RootState } from "@/redux/store";
import React from "react";
import { useDispatch, useSelector } from "react-redux";

function TodoList() {
  const todoList = useSelector((state: RootState) => state.todoReducer.list);
  const dispatch = useDispatch<AppDispatch>();
  const [todo, setTodo] = React.useState("");

  const handleSubmit = () => {
    dispatch(
      addTodo({
        id: Date.now(),
        name: todo,
        done: false,
      })
    );
    setTodo("");
  };

  const handleDelete = (id: number) => {
    dispatch(removeTodo(id));
  };

  const handleToggle = (id: number) => {
    dispatch(toggleTodo(id));
  };

  return (
    <div>
      <input
        type="text"
        onChange={(e) => setTodo(e.target.value)}
        value={todo}
      />
      <button onClick={handleSubmit}>Add</button>
      {todoList.map((todo) => {
        return (
          <div key={todo.id} className="flex">
            <input
              type="checkbox"
              checked={todo.done}
              onChange={() => handleToggle(todo.id)}
            />
            {todo.name}

            <button onClick={() => handleDelete(todo.id)} className="ml-auto">
              🗑️
            </button>
          </div>
        );
      })}
    </div>
  );
}

export default TodoList;


```

Then let's add our component to our home page 
```typescript
import TodoList from "@/components/TodoList";

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
        <TodoList />
      </div>
    </main>
  );
}

```

Here is a simple and quick Nextjs 13 app with Redux and Typescript.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gr2zgas3m6jfydn6nv0s.png)

Note: you could create your custom dispatch and selector to include your type by default in the store file.

Please leave your suggestions to help others since this is a high-level and simple quick guide.

Junior The Dev here, keeping up the grind.