React Todo App with API

Summary: in this tutorial, you will continue integrating the React Todo App with the API server to store the todo list.

Setting up an API server #

First, download the following file and extract it to a directory on your computer such as todo-api:

Download Todo API Server Source Code

Second, open your terminal and navigate to the project directory:

cd todo-api

Third, run the following npm command to install project dependencies:

npm instal

Finally, run the npm start command to start the API server:

npm start

The API server will be running and listening on the port 5000:

http://localhost:5000/

The following table displays the API endpoints:

MethodEndpointDescriptionRequest BodyResponse
GET/todosRetrieve all todo items.NoneJSON array of todos
GET/todos/:idRetrieve a single todo item by its ID.NoneJSON object of the todo item
POST/todosCreate a new todo item.{ "title": string, "completed": integer }JSON object of the created todo item
PUT/todos/:idUpdate an existing todo item by its ID.{ "title": string, "completed": boolean }JSON object of the updated todo item
DELETE/todos/:idDelete a todo item by its ID.None{ "id": integer }

Integrating the API into the React Todo App #

To call an API from React, you can use the built-in Fetch API provided by web browsers.

Displaying the todo list #

When the Todo app starts for the first time, it should call the API GET /todos to retrieve all todo items and display them on the screen.

To do that, we need to:

  • Define a function getTodos that calls the API GET /todos to retrieve all todos items and update the todos state.
  • Execute the getTodos function only for the first time when the app starts.

First, define a new function getTodos() that calls the API and updates the todos state:

const getTodos = async () => {
    const url = 'http://localhost:5000/todos';
    try {
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) {
        throw new Error('Network response was not ok');
      }

      const storedTodos = await response.json();
      // Update the state
      if (storedTodos) setTodos(storedTodos);
    } catch (error) {
      console.error('Error during GET request:', error);
    }
  };

Second, call the getTodos() function once when the component renders for the first time using the useEffect() hook:

useEffect(() => {
  getTodos();
}, []);

In this syntax, the useEffect is a hook in React. A hook is a function that adds functionality to the component.

The useEffect() hook allows you to run a function at a specific point in time. It accepts two arguments:

  • A function
  • An empty array ([]).

The empty array instructs the useEffect() hook to execute the function the first time the component renders. We’ll cover more about React hooks in the upcoming tutorials.

Creating a new todo item #

To create a new todo item, you need to:

  • Call the API POST /todos to create a new todo item in the database.
  • Add the new todo to the current todos state using the setTodos function.

Here’s the modified version of the createTodo() function:

const createTodo = async (title) => {
    // form a new todo
    const newTodo = {
      title: title,
      completed: false,
    };

    // call an API to create a new todo
    const url = 'http://localhost:5000/todos';
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(newTodo),
      });

      if (!response.ok) throw new Error('Network response was not ok');

      const storedTodo = await response.json();

      // set a new state
      const updatedTodos = [...todos, storedTodo];

      setTodos(updatedTodos);
    } catch (error) {
      console.error('Error creating a todo:', error);
    }
  };

Removing a todo item #

To remove a todo item, you need to:

  • Call the API DELETE /todo/:id to delete a todo specified by the ID from the database.
  • Remove the deleted todo from the todos state.

Here’s the new version of the removeTodo() function:

const removeTodo = async (id) => {
    // Delete the todo
    const url = `http://localhost:5000/todos/${id}`;

    try {
      const response = await fetch(url, {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) throw new Error('Network response was not ok');

      // Update the state
      const updatedTodos = todos.filter((todo) => todo.id !== id);
      setTodos(updatedTodos);
    } catch (error) {
      console.error('Error during DELETE request:', error);
      throw error;
    }
  };

Updating a todo item #

To update a todo item, you need to:

  • Call the API PUT /todo/:id to update a todo specified by the id.
  • Update the modified todo in the todos state.

Here’s the new version of the changeTodo() function:

const changeTodo = async (id, newTitle, completed = false) => {
    // Update todo
    const url = `http://localhost:5000/todos/${id}`;

    const data = { title: newTitle, completed };

    try {
      const response = await fetch(url, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      });

      if (!response.ok) {
        throw new Error('Network response was not ok');
      }

      const updatedTodo = await response.json();

      // Update the state
      const updatedTodos = todos.map((todo) => {
        if (todo.id === id) {
          return { ...todo, ...updatedTodo };
        }
        return todo;
      });
      setTodos(updatedTodos);
    } catch (error) {
      console.error('Error during PUT request:', error);
      throw error;
    }
  };

The rest of the Todo app remains the same.

Download the React Todo App with API #

Download the React Todo App with API Source Code

Summary #

  • Use the Fetch API provided by the web browser to call APIs.
  • Use the useEffect hook to run a function once after the component is displayed.

Was this helpful?