Todo list in next js with backend as firebase

In this blog, we will create a simple web application where users can create and manage their to-do lists. We will be using Next.js and TypeScript to create the frontend, and Firebase as the backend service to store the data.

Getting Started

To get started, make sure you have Node.js and npm installed on your computer. Then, create a new Next.js app with TypeScript by running the following commands:

npx create-next-app --typescript todo-app
cd todo-app

Next, install the Firebase SDK by running:

npm install firebase

Firebase Setup

Before we can use Firebase in our app, we need to set up a Firebase project and get our API keys. Here are the steps:

  1. Go to the Firebase Console and create a new project.
  2. Click “Add app” and select “Web” to add a new web app to your project.
  3. Enter a name for your app and click “Register app”.
  4. Copy the Firebase configuration object that appears on the next screen.
  5. Create a new file called firebase.ts in the utils folder of your Next.js app.
  6. Paste the Firebase configuration object into firebase.ts and export it:
    import firebase from 'firebase/app';
    import 'firebase/firestore';
    
    const firebaseConfig = {
      // your Firebase config object here
    };
    
    if (!firebase.apps.length) {
      firebase.initializeApp(firebaseConfig);
    }
    
    export const db = firebase.firestore();
    

     

We are importing the firebase and firestore modules from the Firebase SDK and initializing our app with the Firebase configuration object.

Next, we export the firestore object so that we can use it to interact with our Firebase Firestore database.

Creating the Todo List

Now that we have our Firebase setup, let’s create the todo list app.

  1. Create a new file called Todo.ts in the types folder of your Next.js app. This file will contain the TypeScript interfaces for our todo list items:
    export interface Todo {
      id: string;
      title: string;
      completed: boolean;
    }
    

     

  2. Next, create a new file called TodoItem.tsx in the components folder of your Next.js app. This file will contain the code for rendering a single todo item:
    import { Todo } from '../types/Todo';
    
    interface TodoItemProps {
      todo: Todo;
      onComplete: (id: string) => void;
      onDelete: (id: string) => void;
    }
    
    export default function TodoItem({ todo, onComplete, onDelete }: TodoItemProps) {
      return (
        <div>
          <input type="checkbox" checked={todo.completed} onChange={() => onComplete(todo.id)} />
          <span>{todo.title}</span>
          <button onClick={() => onDelete(todo.id)}>Delete</button>
        </div>
      );
    }
    

    Here, we define the TodoItem component which takes in a todo object and two callback functions: onComplete and onDelete. The onComplete function is called when the user marks the todo item as completed, and the onDelete function is called when the user clicks the “Delete” button.

  3. Create a new file called TodoList.tsx in the components folder of your Next.js app. This file will contain the code for rendering the list of todo items:
    import React from 'react';
    import { Todo } from '../types';
    
    interface Props {
      todos: Todo[];
      onDelete: (id: string) => void;
    }
    
    const TodoList: React.FC<Props> = ({ todos, onDelete }) => {
      return (
        <ul>
          {todos.map((todo) => (
            <li key={todo.id}>
              {todo.text}
              <button onClick={() => onDelete(todo.id)}>Delete</button>
            </li>
          ))}
        </ul>
      );
    };
    
    export default TodoList;
    
    

    In this code, we define a new functional component called TodoList. This component takes two props: todos, which is an array of todo items, and onDelete, which is a function that will be called when the user clicks the “Delete” button for a todo item.

    Inside the TodoList component, we use the map method to iterate over the todos array and render a list item for each todo item. For each todo item, we display its text and a “Delete” button that, when clicked, calls the onDelete function with the todo item’s ID.

    Next, let’s create a form for adding new todo items. Create a new file called TodoForm.tsx in the components folder:

    import React, { useState } from 'react';
    
    interface Props {
      onAdd: (text: string) => void;
    }
    
    const TodoForm: React.FC<Props> = ({ onAdd }) => {
      const [text, setText] = useState('');
    
      const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        onAdd(text);
        setText('');
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <input
            type="text"
            value={text}
            onChange={(event) => setText(event.target.value)}
          />
          <button type="submit">Add Todo</button>
        </form>
      );
    };
    
    export default TodoForm;
    

    In this code, we define another functional component called TodoForm. This component takes a single prop: onAdd, which is a function that will be called when the user submits the form to add a new todo item.

    Inside the TodoForm component, we use the useState hook to define a new state variable called text, which will hold the value of the input field where the user types in the new todo item’s text.

    We also define a handleSubmit function that will be called when the user submits the form. This function prevents the default form submission behavior, calls the onAdd function with the current value of the text state variable, and then resets the text state variable to an empty string.

    Finally, we render a form with an input field and a “Add Todo” button. The input field’s value is set to the text state variable, and we use the onChange event to update the text state variable as the user types.

    Now that we have the TodoList and TodoForm components, let’s create a new page where the user can see their todo list and add new items. Create a new file called index.tsx in the pages folder:

    import { useState } from 'react';
    import Head from 'next/head';
    import TodoList from '../components/TodoList';
    
    interface TodoItem {
      id: number;
      title: string;
      completed: boolean;
    }
    
    export default function Home() {
      const [todoItems, setTodoItems] = useState<TodoItem[]>([]);
    
      const handleAddTodo = (title: string) => {
        const newTodoItem: TodoItem = {
          id: Date.now(),
          title: title,
          completed: false,
        };
        setTodoItems([...todoItems, newTodoItem]);
      };
    
      const handleRemoveTodo = (id: number) => {
        const updatedTodoItems = todoItems.filter((item) => item.id !== id);
        setTodoItems(updatedTodoItems);
      };
    
      const handleToggleTodo = (id: number) => {
        const updatedTodoItems = todoItems.map((item) =>
          item.id === id ? { ...item, completed: !item.completed } : item
        );
        setTodoItems(updatedTodoItems);
      };
    
      return (
        <div>
          <Head>
            <title>Todo App</title>
            <link rel="icon" href="/favicon.ico" />
          </Head>
    
          <main>
            <h1>Todo App</h1>
            <TodoList
              todoItems={todoItems}
              onAddTodo={handleAddTodo}
              onRemoveTodo={handleRemoveTodo}
              onToggleTodo={handleToggleTodo}
            />
          </main>
        </div>
      );
    }
    

    In this code, we import the TodoList component we created earlier and render it in the main section of the page. We also define some state using the useState hook to keep track of the list of todo items. We pass down three callback functions as props to the TodoList component – onAddTodo, onRemoveTodo, and onToggleTodo – which are used to add, remove, and toggle todo items respectively. When these functions are called, they update the state using the setTodoItems function. Finally, we add some basic styling to the page using CSS.

Thanks for reading the blog.

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories