🧑‍💻Todo using NextJS 13+, ( useContext, useReducer, TypeScript ).
Published: 2023-08-27 16:17:45

**This is a TODO List app made using NextJs 13+ (latest version).**

## The Final Todo App : 

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


##Tools used are : 
1. useContext
2. useReducer
4. TypeScript


## All Steps

## Step 1 : First Setup the Nextjs 13 using : 

```js
npx create-next-app@latest
```
and setup the nextjs app following all commands.

## Step 2 : Make a folder structure like this : 

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


## Step 3 : First make a reducer : 
_(NewReducer.ts)_
```js
export interface Todo {
  id?: number;
  todoName: string;
  completed: boolean;
}

export interface StateType {
  todos: Todo[];
}

export interface ActionType {
  type: "CREATE_TODO" | "DELETE_TODO" | "TOOGLE_TODO";
  payload: Todo;
}

export const INITIAL_STATE = {
  todos: [],
};

export const reducer = (state: StateType, action: ActionType) => {
  switch (action.type) {
    case "CREATE_TODO":
      return {
        ...state,
        todos: [...state.todos, action.payload],
      };

    case "DELETE_TODO":
      return {
        ...state,
        todos: state.todos.filter((todo) => todo.id !== action.payload.id),
      };

    case "TOOGLE_TODO":
      return {
        ...state,
        todos: state.todos.map((todo) => {
          if (todo.id === action.payload.id) {
            return { ...todo, completed: !todo.completed };
          }
          return todo;
        }),
      };

    default:
      return state;
  }
};

```

## Step 4 : Create a context 
_(NewContext.tsx)_

```js
"use client";

import React, { createContext, useContext, useReducer } from "react";
import {
  StateType,
  ActionType,
  INITIAL_STATE,
  reducer,
} from "@/reducers/NewReducer";

interface NewContextProps {
  children: React.ReactNode;
}

interface NewContextValue {
  state: StateType;
  dispatch: React.Dispatch<ActionType>;
}

const NewContext = createContext<NewContextValue>({
  state: INITIAL_STATE,
  dispatch: () => {},
});

export const useNewContext = () => useContext(NewContext);

export const NewContextProvider: React.FC<NewContextProps> = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
  return (
    <NewContext.Provider value={{ state, dispatch }}>
      {children}
    </NewContext.Provider>
  );
};

```

## Step 5 : 
_(Todo.tsx)_

```js

"use client";

import { useNewContext } from "@/context/NewContext";
import { useState } from "react";

interface Todo {
  id?: number;
  todoName: string;
  completed: boolean;
}

const Todo = () => {
  const { state, dispatch } = useNewContext();

  const [todo, setTodo] = useState<Todo>({
    todoName: "",
    completed: false,
  });

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setTodo({ ...todo, todoName: e.target.value });
  };

  const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const newTodo = {
      id: Date.now(),
      todoName: todo.todoName,
      completed: false,
    };
    dispatch({ type: "CREATE_TODO", payload: newTodo });
    setTodo({ todoName: "", completed: false });
  };

  return (
    <div className="flex flex-col">
      <form
        onSubmit={handleFormSubmit}
        className="w-[300px] m-auto flex flex-col gap-2"
      >
        <input
          value={todo.todoName}
          onChange={handleInputChange}
          placeholder="Enter a Todo"
          className="border-[1.5px] border-black p-3 m-2"
        />
        <button type="submit" className="btn">
          Create Todo
        </button>
      </form>
      <h1 className="underline mt-9 mb-3 font-bold text-xl m-auto">
        Todos List
      </h1>

      {state.todos.length > 0 ? (
        state.todos.map((todo, index) => (
          <div
            key={todo.id}
            className="flex justify-between shadow-md bg-slate-100 w-[300px] m-auto my-3 p-4 text-xl font-bold"
          >
            <h1
              onClick={() => dispatch({ type: "TOOGLE_TODO", payload: todo })}
              className={`${
                todo.completed ? "line-through opacity-60" : "no-underline"
              } cursor-pointer`}
            >
              {index + 1}. {todo.todoName}
            </h1>
            <button
              onClick={() =>
                dispatch({
                  type: "DELETE_TODO",
                  payload: todo,
                })
              }
              className="text-red-500 border-[2.5px] border-red-500 px-2"
            >
              Delete
            </button>
          </div>
        ))
      ) : (
        <h1 className="text-center font-bold text-red-600">No Todos :(</h1>
      )}
    </div>
  );
};

export default Todo;

```


Any questions related to this code feel free to ask :)