React.js is a popular JavaScript library used for building user interfaces. It was developed by Facebook and has quickly become one of the most popular libraries in the JavaScript community. React.js makes it easy to create reusable components and manage state, making it a great choice for building web applications.
In this article, we'll walk through the process of building a To-Do List app using React.js. We'll cover the basics of setting up a React project, creating components, managing state, and handling user interactions. By the end of this article, you'll have a good understanding of how to build a simple web application using React.js.
Building a To-Do List App Using React
Now, let's proceed with the first step.
Step 1: Setting up the environment
The first step to building a To-Do List app using React is to set up the development environment. We can do this by creating a new React project using Create React App.
To get started, open your terminal and type the following command:
npx create-react-app todo-list-app
This will create a new React project named todo-list-app
. Once the project is created, navigate to the project directory using the following command:
cd todo-list-app
Step 2: Creating the To-Do List component
Now that we have our project set up, let's create our first React component, the To-Do List component.
In the src
folder of our project, create a new file named TodoList.js
. In this file, we will create a functional component that will render our To-Do List.
Here's the code to create the component:
import React from 'react';
function TodoList() {
return (
<div>
<h1>To-Do List</h1>
{/* Add your To-Do List code here */}
</div>
);
}
export default TodoList;
This code imports React and creates a functional component named TodoList
. The TodoList
component returns a div with an h1 element that displays the title of our To-Do List.
Now that we have created our To-Do List component, let's move on to the next step.
Step 3: Creating the Add Task component
In order to add tasks to our To-Do List, we need to create an Add Task component. This component will be responsible for taking user input and adding it to our To-Do List.
In the src
folder, create a new file named AddTask.js
. In this file, we will create a class component that will render a form for the user to add a new task.
Here's the code to create the component:
import React, { Component } from 'react';
class AddTask extends Component {
state = {
task: ''
};
handleInputChange = e => {
this.setState({ task: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.props.onAddTask(this.state.task);
this.setState({ task: '' });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Add Task"
value={this.state.task}
onChange={this.handleInputChange}
/>
<button>Add</button>
</form>
);
}
}
export default AddTask;
This code imports React and creates a class component named AddTask
. The AddTask
component contains a state object with a task
property that represents the input value of the form. We also have two methods, handleInputChange
and handleSubmit
. handleInputChange
updates the task
property of the state object with the current value of the input field, while handleSubmit
prevents the default form submission behavior and calls the onAddTask
method with the current value of the input field. Finally, the render
method returns a form with an input field and a button.
Now that we have created our Add Task component, let's move on to the next step.
Step 4: Creating the Task component
To display the tasks in our To-Do List, we need to create a Task component. This component will render each individual task in our list.
In the src
folder, create a new file named Task.js
. In this file, we will create a functional component that will render a single task.
Here's the code to create the component:
import React from 'react';
function Task(props) {
return (
<li>
{props.task}
<button onClick={() => props.onDeleteTask(props.id)}>Delete</button>
</li>
);
}
export default Task;
This code imports React and creates a functional component named Task
. The Task
component takes in two props, task
and onDeleteTask
. task
is the task text that we want to display, and onDeleteTask
is a function that will be called when the delete button is clicked. The render
method returns a list item that displays the task text and a delete button. When the delete button is clicked, it calls the onDeleteTask
function with the task's id as an argument.
Step 5: Adding state to the To-Do List component
Now that we have created our individual components, we can start building out our To-Do List component. First, we need to add some state to the component to keep track of the tasks.
In the TodoList.js
file, add the following code:
import React, { Component } from 'react';
import Task from './Task';
import AddTask from './AddTask';
class TodoList extends Component {
state = {
tasks: [
{ id: 1, task: 'Buy groceries' },
{ id: 2, task: 'Go for a walk' }
]
};
renderTasks() {
return this.state.tasks.map(task => (
<Task key={task.id} id={task.id} task={task.task} onDeleteTask={this.handleDeleteTask} />
));
}
handleAddTask = task => {
const tasks = [...this.state.tasks];
tasks.push({ id: tasks.length + 1, task });
this.setState({ tasks });
};
handleDeleteTask = id => {
const tasks = [...this.state.tasks];
const index = tasks.findIndex(task => task.id === id);
tasks.splice(index, 1);
this.setState({ tasks });
};
render() {
return (
<div>
<h1>To-Do List</h1>
<AddTask onAddTask={this.handleAddTask} />
<ul>{this.renderTasks()}</ul>
</div>
);
}
}
export default TodoList;
This code imports React, as well as our Task
and AddTask
components. We create a class component named TodoList
and add some initial state with two tasks. We also add two methods, handleAddTask
and handleDeleteTask
, which will be called when a task is added or deleted. handleAddTask
creates a new task object and adds it to the tasks
array in the state. handleDeleteTask
removes the task with the specified id from the tasks
array in the state.
We also add a renderTasks
method, which maps over the tasks
array in the state and renders a Task
component for each task. We pass in the id
, task
, and onDeleteTask
props to each Task
component.
Finally, the render
method returns our To-Do List component with the AddTask
and Task
components.
Now that we have added state to our To-Do List component, let's move on to the next step.
Step 6: Adding new tasks to the To-Do List
Now that we have added state to our To-Do List component, let's add the ability to add new tasks.
In the AddTask.js
file, add the following code:
import React, { Component } from 'react';
class AddTask extends Component {
state = {
task: ''
};
handleChange = e => {
this.setState({ task: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.props.onAddTask(this.state.task);
this.setState({ task: '' });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.task} onChange={this.handleChange} />
<button>Add Task</button>
</form>
);
}
}
export default AddTask;
This code imports React and creates a class component named AddTask
. We add some initial state with an empty task string. We also add two methods, handleChange
and handleSubmit
, which will be called when the input field is changed or when the form is submitted.
handleChange
updates the state with the new task text. handleSubmit
prevents the default form submission behavior, calls the onAddTask
prop with the new task text as an argument, and then clears the input field by resetting the task
state.
Finally, the render
method returns a form with an input field and a submit button. The input field's value is bound to the task
state, and the handleChange
method is called whenever the input field is changed.
In the TodoList.js
file, we have already added the AddTask
component to the render method of the TodoList
component, and we have added a handleAddTask
method that is called when a new task is added.
Step 7: Marking tasks as completed
Now, let's add the ability to mark tasks as completed. We'll add a checkbox to each task and update the state of the task when the checkbox is clicked.
In the TodoList.js
file, update the Task
component as follows:
class Task extends Component {
handleToggleCompleted = () => {
this.props.onToggleCompleted(this.props.task.id);
};
render() {
const { task } = this.props;
return (
<div>
<input
type="checkbox"
checked={task.completed}
onChange={this.handleToggleCompleted}
/>
{task.text}
</div>
);
}
}
We add a new method called handleToggleCompleted
that is called when the checkbox is clicked. This method calls the onToggleCompleted
prop with the id
of the task as an argument.
In the TodoList
component, add the following method:
handleToggleCompleted = id => {
const { tasks } = this.state;
const index = tasks.findIndex(task => task.id === id);
const updatedTasks = [
...tasks.slice(0, index),
{ ...tasks[index], completed: !tasks[index].completed },
...tasks.slice(index + 1)
];
this.setState({ tasks: updatedTasks });
};
This method takes the id
of the task that was clicked and uses it to find the index of the task in the tasks
array. We then create a new array of tasks with the task at the given index updated to toggle the completed
state.
Finally, we set the state of the tasks
array to the updated array.
With this update, when a user clicks on a checkbox, the corresponding task will be marked as completed, and the checkbox will be checked.
Step 8: Filtering tasks
Let's add a filter to our To-Do List, so the user can toggle between seeing all tasks, completed tasks, or incomplete tasks.
In the TodoList.js
file, add the following state to the TodoList
component:
state = {
tasks: [],
filter: 'all'
};
We add a new filter
state that starts with the value 'all'.
Next, add the following methods to the TodoList
component:
handleFilterChange = filter => {
this.setState({ filter });
};
getFilteredTasks = () => {
const { tasks, filter } = this.state;
switch (filter) {
case 'completed':
return tasks.filter(task => task.completed);
case 'incomplete':
return tasks.filter(task => !task.completed);
default:
return tasks;
}
};
handleFilterChange
is called when the user clicks on a filter button. It takes the filter as an argument and updates the filter
state accordingly.
getFilteredTasks
returns the tasks that match the current filter.
In the render
method of the TodoList
component, update the code to include filter buttons and to display only the filtered tasks:
render() {
const { tasks, filter } = this.state;
const filteredTasks = this.getFilteredTasks();
return (
<div>
<h1>To-Do List</h1>
<AddTask onAddTask={this.handleAddTask} />
<div>
<button onClick={() => this.handleFilterChange('all')} disabled={filter === 'all'}>
All
</button>
<button onClick={() => this.handleFilterChange('completed')} disabled={filter === 'completed'}>
Completed
</button>
<button onClick={() => this.handleFilterChange('incomplete')} disabled={filter === 'incomplete'}>
Incomplete
</button>
</div>
{filteredTasks.map(task => (
<Task key={task.id} task={task} onToggleCompleted={this.handleToggleCompleted} />
))}
</div>
);
}
We create three filter buttons that call the handleFilterChange
method when clicked. We also disable the button that matches the current filter.
Finally, we update the filteredTasks
variable to contain only the tasks that match the current filter.
With these changes, the user can now toggle between seeing all tasks, completed tasks, or incomplete tasks.
To run the code, open your terminal and navigate to the root folder of your project. Then, run the following command:
npm start
This will start the development server and open the app in your default web browser. You should now be able to interact with the To-Do List app you just built!
Conclusion
In conclusion, building a To-Do List app using React can be a great way to learn the basics of React and practice building user interfaces. We started by setting up our project using create-react-app, and then created several components including TodoList
, AddTask
, and Task
. We also used React's state to keep track of our tasks and to allow users to toggle the completion status of each task. Finally, we added a filter to our To-Do List, so the user can toggle between seeing all tasks, completed tasks, or incomplete tasks.
Throughout this tutorial, we've covered several important concepts in React including components, state, props, and event handling. While this app is relatively simple, it provides a great foundation for building more complex apps in the future.
I hope you found this tutorial helpful and that you're excited to continue learning and building with React!