Setting Up the Project with Vite

Author: Oleksandr Vlasov

Live Demo: https://todo-application-rho-five.vercel.app/

Blog RoyalZSoftware https://royalzsoftware.de/react-hooks-createcontext-usecontext-usememo

As a junior React developer, I recently completed a project to build a Todo Application using React with TypeScript. The primary goal was to create a functional app and enhance my understanding of React hooks like useState, useMemo, and especially useContext for state management.

This app enables users to add, delete, mark tasks as complete, and download the to-do list as a CSV file. Here’s an overview of how I structured the app and applied these React hooks.

1. Setting Up the Project with Vite

To kickstart the project, I used Vite to create a fast, TypeScript-ready React environment:

npm create vite@latest my-todo-app --template react-ts

Managing Todos with useState

The app’s core functionality is the to-do list. Here’s how I managed the state with useState.

TypeScript Code:

export interface Todo {
  text: string;
  completed: boolean;
}

const [todos, setTodos] = useState<Todo[]>([]);

Avoiding Prop Drilling with useContext

To avoid prop drilling, I used createContext to create a global state. Components accessed the state using useContext.

TypeScript Code:

const TodoContext = createContext<TodoContextType | undefined>(undefined);
const { todos, addTodo, deleteTodo, toggleTodo } = useContext(TodoContext);

Marking Todos as Complete/Incomplete

A checkbox toggles the completion status of each task.

TypeScript Code:

function toggleTodo(index: number) {
  setTodos((prevTodos) =>
    prevTodos.map((todo, i) =>
      i === index ? { ...todo, completed: !todo.completed } : todo
    )
  );
}

Deleting Todos

To delete a todo item, I used the filter() method.

TypeScript Code:

function deleteTodo(index: number) {
  setTodos((prevTodos) => prevTodos.filter((_, i) => i !== index));
}

Downloading the Todo List as CSV

I added a feature to download the to-do list as a CSV file.

TypeScript Code:

const downloadCSV = () => {
  const dataCSV =
    "task,completed\n" +
    todos
      .map(
        (todo) => `${todo.text}, ${todo.completed ? "done" : "not completed"}`
      )
      .join("\n");

  const blob = new Blob([dataCSV], { type: "text/csv" });
  const url = window.URL.createObjectURL(blob);

  const a = document.createElement("a");
  a.href = url;
  a.download = "todo-list.csv";
  a.click();

  window.URL.revokeObjectURL(url);
};