Building a Modern ToDo List with React

Overview

In this tutorial, we’ll walk through the process of building a modern and stylish ToDo list using React. We’ll cover the basics of React, including state management with hooks, handling user input, and styling the application for better visual appeal. By the end of this tutorial, you’ll have a solid understanding of building React components and creating interactive user interfaces. Let’s dive in!

Step 1 : Setting up the project:

Have a look at Step 1  of the following blog if you wanna understand how to setup a vite project from scratch.

Step 2: Creating the App Component:

  • App.jsx:

				
					import React, { useState } from 'react';

const App = () => {
  const [tasks, setTasks] = useState([]);
  const [newTask, setNewTask] = useState('');

  const handleInputChange = (event) => {
    setNewTask(event.target.value);
  };

  const addTask = () => {
    if (newTask.trim() !== '') {
      setTasks([...tasks, newTask]);
      setNewTask('');
    }
  };

  const deleteTask = (index) => {
    setTasks(tasks.filter((_, i) => i !== index));
  };

  return (
    <div className="todo-container">
      <h2 className="todo-heading">To-Do List</h2>
      <div className="input-container">
        <input
          className="task-input"
          type="text"
          value={newTask}
          onChange={handleInputChange}
          placeholder="Add new task"
        />
        <button className="add-button" onClick={addTask}>Add</button>
      </div>
      <ul className="task-list">
        {tasks.map((task, index) => (
          <li key={index} className="task-item">
            {task}
            <button className="delete-button" onClick={() => deleteTask(index)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default App;

				
			
  • Index.css:

				
					.todo-container {
  max-width: 400px;
  margin: 0 auto;
}

.todo-heading {
  text-align: center;
  color: #333;
}

.input-container {
  display: flex;
  margin-bottom: 10px;
}

.task-input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 16px;
}

.add-button {
  padding: 8px 16px;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  margin-left: 10px;
}

.add-button:hover {
  background-color: #45a049;
}

.task-list {
  list-style-type: none;
  padding: 0;
}

.task-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  border-bottom: 1px solid #ccc;
}

.delete-button {
  padding: 5px 10px;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.delete-button:hover {
  background-color: #e53935;
}


				
			

Note: You can delete the app.css.

Step 3: Code Explanation:

  • Setting up the react component as app.jsx :
    • In this step, we start by importing React and the useState hook from the react package. React is a JavaScript library for building user interfaces, and hooks are functions that let you use state and other React features in functional components. We define a functional component called App, which will represent our ToDo list application.
				
					import React, { useState } from 'react';
import './ToDoList.css';

const App = () => {
  // Component logic will go here
};

				
			
  •  Managing State:
    • React allows us to manage component state using the useState hook. We use the useState hook to define two pieces of state: tasks and newTask.

      • tasks: This state holds an array of tasks in our ToDo list.

      • newTask: This state holds the value of the input field where users can add new tasks.
				
					const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState('');

				
			
  • Handling Input Change:
    • To handle changes in the input field (where users can add new tasks), we define a function called handleInputChange. This function updates the newTask state whenever the value of the input field changes. We achieve this by accessing the value property of the input field through the event object.
				
					const handleInputChange = (event) => {
  setNewTask(event.target.value);
};

				
			
  • Adding a New Task:
    • When the user clicks the “Add” button, we want to add the new task to our list of tasks. We define a function called addTask to accomplish this.

      • First, we check if the newTask is not empty (after trimming any whitespace).
      • If it’s not empty, we create a new array containing the existing tasks (...tasks) along with the new task (newTask), and update the tasks state with this new array.
      • We also clear the input field by setting the newTask state to an empty string.
				
					const addTask = () => {
  if (newTask.trim() !== '') {
    setTasks([...tasks, newTask]);
    setNewTask('');
  }
};

				
			
  • Deleting a Task:
    • If a user wants to delete a task from the list, they can click the “Delete” button next to that task. We define a function called deleteTask to handle this action.

      • This function takes the index of the task to be deleted as a parameter.
      • We use the filter method to create a new array of tasks that excludes the task at the specified index.
      • We update the tasks state with this new array, effectively removing the task from the list.
				
					const deleteTask = (index) => {
  setTasks(tasks.filter((_, i) => i !== index));
};

				
			
  • Rendering the Component :
    • Here, we define the JSX (JavaScript XML) structure that represents our ToDo list component.

      • We use HTML-like syntax to create elements such as headings (<h2>), input fields (<input>), buttons (<button>), and lists (<ul> and <li>).
      • We assign class names to these elements to style them using CSS.
      • We use curly braces {} to embed JavaScript expressions (e.g., {newTask}) within JSX.
      • We use event handlers like onChange and onClick to listen for user actions and call the corresponding functions (handleInputChange and addTask or deleteTask) when those events occur.
				
					return (
  <div className="todo-container">
    <h2 className="todo-heading">To-Do List</h2>
    <div className="input-container">
      <input
        className="task-input"
        type="text"
        value={newTask}
        onChange={handleInputChange}
        placeholder="Add new task"
      />
      <button className="add-button" onClick={addTask}>Add</button>
    </div>
    <ul className="task-list">
      {tasks.map((task, index) => (
        <li key={index} className="task-item">
          {task}
          <button className="delete-button" onClick={() => deleteTask(index)}>Delete</button>
        </li>
      ))}
    </ul>
  </div>
);

				
			
  • Exporting the Component :
    • Finally, we export the App component so that it can be imported and used in other parts of our application. This allows us to reuse the component and keep our code organized.
				
					export default App;

				
			

Step 4: Running the Application:

Now that we’ve completed our coding, let’s run the application. In your terminal, navigate to the project directory and run:

				
					npm start
				
			

Conclusion:

Congratulations! You’ve successfully built a modern and stylish ToDo list using React. Throughout this tutorial, we covered the basics of React components, state management with hooks, handling user input, and styling the application using CSS. This project serves as a great starting point for further exploration of React and building more complex applications. Keep experimenting and happy coding!