ReactJs Step-By-Step Tutorial Series — Part 4 — Build ToDo Application Using ReactJS

Hello Readers,

This is the Part-4 of our ReactJs tutorial series. In this tutorial, we will make a simple ToDo application, but before that, you can check and refer to any previous article here:

Quick links for our ReactJs Series:

Tutorial #1 — Introduction and Installation of ReactJS

Tutorial #2 — ReactJS Components

Tutorial #3 — ReactJS Components Communication

Tutorial #4 — Build ToDo Application Using ReactJS (This Tutorial)

Tutorial #5 — Deploy ToDo Application to Github pages

What We’ll Build Today

  • Create a ToDo Application

We will make a basic to-do list application where we can add, update and delete items from a list. With this application, we will also learn about how to use Bootstrap and Font-awesome icons and will also apply some styles conditionally.

So let’s start with it..!

Create Todo Application

As we have already created this ToDo application using React, we will continue with this only.

If you haven’t created it yet then you can follow it from our Part-1 here.

Display all Todos

We will start by creating a ToDoList (class) component. Here we will have a static array of ToDo list items.

import React, { Component } from "react";export default class TodoList extends Component {state = {
todos: [
{ Id: '1', Title: 'Push your code to github', Status: 'Done' },
{ Id: '2', Title: 'Email to your manager', Status: 'Pending' }
]
};
render() {
return (
<div>
<h1>TodoList </h1>
</div>
);
}
}

Now let’s loop through this array and display these records using simple <table> tag. Note that with React we are using JSX syntax so here we can display this array using this.state.todos.map(). This map() will iterate each item of the loop and display it one by one.

To modify this ToDoList.js as below:

import React, { Component } from "react";export default class TodoList extends Component {state = {
todos: [
{ Id: '1', Title: 'Push your code to github', Status: 'Done' },
{ Id: '2', Title: 'Email to your manager', Status: 'Pending' }
]
};
render() {
return (
<div>
<h1>TodoList </h1>
<table>
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{this.state.todos.map(x => {
return (
<tr key={x.Id}>
<td>{x.Id}</td>
<td>{x.Title}</td>
<td >{x.Status}</td>
<td>
<button>Delete</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}

Now call this ToDo component on App.js and run this app and we can see all ToDos on the browser:

Now before going into the more details we quickly see how we can use Bootstrap and Font-awesome icons in our React application.

Use Bootstrap

1)To use the Bootstrap, install its package from npm into your app.

npm  install bootstrap

2) Now give this BootstrapCDN path on index.html

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

3) Now on our ToDoList.js we just apply Bootstrap Styling.

So on <table> tag use it’s class “table”.

......<table className=”table”>...</table>
...

Note above that, in HTML, we can use a class as an attribute name but in JSX we cannot use the word class. We have to use className instead. Because class is a reserved word in JavaScript and JSX will be converted to javaScript.

Now run the app and you can see the changes.

Use Font-awesome

1)To use the Font-awesome, install all given packages from npm into your app.

npm i --save @fortawesome/fontawesome-svg-corenpm i --save @fortawesome/free-solid-svg-iconsnpm i --save @fortawesome/react-fontawesome

2) Now on App.js import the library for the font-awesome

import { library } from "@fortawesome/fontawesome-svg-core";import { faTrash, faPlus, faEdit } from "@fortawesome/free-solid-svg-icons";library.add(faTrash, faEdit, faPlus);

Above we have also included the library for whatever the icons we want to use in our application.

3) Now open the ToDoList.js and apply the trash icon on our Delete button.

For this first import the font-awesome package here:

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

Now change button as below:

<button className="btn btn-primary">
<span>
<FontAwesomeIcon icon="trash"></FontAwesomeIcon>
</span>
</button>

Now go to the browser and see this icon.

So this same way, we will also have an Edit button. So put it after the Delete button.

<button className="btn btn-primary">
<span>
<FontAwesomeIcon icon="edit"></FontAwesomeIcon>
</span>
</button>

Remove to-do item from the list

Ok, so now let’s have Click event listener for these two buttons.

So we will just declare and attach deleteToDo() function to this Delete button.

deleteToDo = (todo) => {
const filteredItems = this.state.todos.filter(x => x.Id !== todo.Id);
this.setState({
todos: filteredItems
});
};
<button className="btn btn-primary" onClick={() => this.deleteToDo(x)}>
<span>
<FontAwesomeIcon icon="trash"></FontAwesomeIcon>
</span>
</button>

Note that this deleteToDo() function will expect an argument — which list item is going to be deleted. And as I said before about this.setState(), we have to use it to update our todo array. And inside this deleteToDo() function we are just filtering our array-like we do normally.

So click on the Delete button and you can see it is removing items from this array. So the state is updating dynamically, yeah..!!

Update to-do item

Now let’s Edit this ToDo list item. For this, we will make a function editToDo() and call it on the Edit button.

editToDo = (x) => {
this.setState(state => ({
todos: state.todos.map(todo => {
if (todo.Id === x.Id) {
return {
...todo,
Status: todo.Status === "Done" ? "Pending" : "Done"
};
} else {
return todo;
}
})
}));
};
<button className="btn btn-primary" onClick={() => this.editToDo(x)}>
<span>
<FontAwesomeIcon icon="edit"></FontAwesomeIcon>
</span>
</button>

In this editTodo() function, we just updating the status of the current to-do list item. This means if the status is ‘pending’ then we will update it to ‘done’ and vice versa.

Here note this line …todo inside this editToDo() function. This three dots() is called as Spread Operator. By using this, it will keep our todos array intact and in the next line, we are just updating the value of the status attribute, so the other two attributes — id and title will not be changed.

So now run this code and update the status.

Here is the ToDoList.js for the reference:

import React, { Component } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export default class TodoList extends Component {state = {
todos: [
{ Id: '1', Title: 'Push your code to github', Status: 'Done' },
{ Id: '2', Title: 'Email to your manager', Status: 'Pending' }
]
};
deleteToDo = (todo) => {
const filteredItems = this.state.todos.filter(x => x.Id !== todo.Id);
this.setState({
todos: filteredItems
});
};
addToDo = (todo) => {
this.setState({
todos: [...this.state.todos, todo]
});
};
editToDo = (x) => {
this.setState(state => ({
todos: state.todos.map(todo => {
if (todo.Id === x.Id) {
return {
...todo,
Status: todo.Status === "Done" ? "Pending" : "Done"
};
} else {
return todo;
}
})
}));
};
render() {
return (
<div>
<h1>TodoList </h1>
<table className="table" >
<thead>
<tr>
<th>Id</th>
<th>Title</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{this.state.todos.map(x => {
return (
<tr key={x.Id}>
<td>{x.Id}</td>
<td>{x.Title}</td>
<td>{x.Status}</td>
<td>
<button className="btn btn-primary" onClick={() => this.deleteToDo(x)} >
<span>
<FontAwesomeIcon icon="trash"></FontAwesomeIcon>
</span>
</button>
|
<button className="btn btn-primary" onClick={() => this.editToDo(x)}>
<span>
<FontAwesomeIcon icon="edit"></FontAwesomeIcon>
</span>
</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}

Apply the CSS styling conditionally

Now let’s apply some styling. What we do is, if the status is ‘pending’ then we will display it in red color and if ‘done’ then it should be displayed in Green color. And we will check the status conditionally on our ToDo.js.

So let’s apply this single line of code our <td> which is displaying the status:

<td style={{ color: x.Status === "Done" ? "green" : "red" }}>{x.Status}</td>

And run this app and see the output:

Add to-do item to the list

To add a new to-do item, we have to make a simple form and by submitting that form we will add that list item to our original todos array.

For this let’s create another component as AddToDo.js. Inside this component, we will have our Add form. And then we will call this Add component to our ToDo.js.

AddToDo.js

import React, { Component } from "react";
export default class AddTodo extends Component {

render() {
return (
<div>
<h3>
Add ToDo
</h3>
<form>
<div className="form-group" >
<input value={this.state.Id} className="form-control" placeholder="Enter Id" />
</div>
<div className="form-group" >
<input value={this.state.Title} className="form-control" placeholder="Enter Title" />
</div>
<div className="form-group">
<select value={this.state.Status} className="form-control" >
<option value="Done" >Done</option>
<option value="Pending" >Pending</option>
</select>
</div>
<button type="submit" className="form-control btn btn-primary" >Add Todo</button>
</form>
</div>
);
}
}

So above we have just designed our Add ToDo form and inside the form, we have added input for Id, Title and Status and one submit button. Also, apply some basic bootstrap class for these inputs.

Now we need to import this AddToDo component and call it on our ToDoList.js.

import AddTodo from './AddTodo';

render() {
return (
<div>
<AddTodo></AddTodo>
<h1>TodoList </h1>
<table className="table" >
<thead>

Now save this and check it first.

Now next step is to fetch the updated value of all inputs and drop down and then pass it to the original todos array.

So to fetch the latest value of input box we will declare it’s onChange() function and inside that function, we will just assign this updated value to our local property. So for that, we will create that local variable first and then update it states meaning its value from onChange().

So here are the variables declaration and onChange() handlers for all 3 inputs — id, title, and status.

AddToDo.js

state = {
Id: "",
Title: "",
Status: "Pending"
};
handleIdChange = (event) => {
this.setState({
Id: event.target.value
});
};
handleTitleChange = (event) => {
this.setState({
Title: event.target.value
});
}
handleStatusChange = (event) => {
this.setState({
Status: event.target.value
});
};

So by now our all properties/variables have new updated value and we will use these properties when we submit this form.

So let’s create form submit event and call it on our form tag and also call onChange() event for all the inputs.

AddToDo.js

import React, { Component } from "react";
export default class AddTodo extends Component {
state = {
Id: "",
Title: "",
Status: "Pending"
};
handleIdChange = (event) => {
this.setState({
Id: event.target.value
});
};
handleTitleChange = (event) => {
this.setState({
Title: event.target.value
});
}
handleStatusChange = (event) => {
this.setState({
Status: event.target.value
});
};
handleToDoSubmit = (event) => {
event.preventDefault();
this.props.onAdd({
Id: this.state.Id,
Title: this.state.Title,
Status: this.state.Status
});
this.setState({
Id: "",
Title: "",
Status: "Pending"
});
};
render() {
return (
<div>
<h3>
Add ToDo
</h3>
<form onSubmit={this.handleToDoSubmit} >
<div className="form-group" >
<input value={this.state.Id} onChange={this.handleIdChange} className="form-control" placeholder="Enter Id" />
</div>
<div className="form-group" >
<input value={this.state.Title} onChange={this.handleTitleChange} className="form-control" placeholder="Enter Title" />
</div>
<div className="form-group">
<select value={this.state.Status} onChange={this.handleStatusChange} className="form-control" >
<option value="Done" >Done</option>
<option value="Pending" >Pending</option>
</select>
</div>
<button type="submit" className="form-control btn btn-primary" >Add Todo</button>
</form>
</div>
);
}
}

Now we need to call this child(AddToDo) component’s function on parent(ToDoList) component.

So remember we have added <AddToDo></AddToDo> tag on ToDoList.js

So it is calling our child component right.! so here we will bind our submit event method of our AddToDo component. So it will actually handle and update our todos array. For that, we need to have one last method and that is addTodo(). This addToDo() will be on ToDoList.js file and we will call it from our <AddToDo></AddToDo> tag as I said before.

ToDoList.js

addToDo = (todo) => {
this.setState({
todos: [...this.state.todos, todo]
});
};

render() {
return (
<div>
<AddTodo onAdd={this.addToDo}></AddTodo>
<h1>TodoList </h1>
<table className="table" >
<thead>

On this line <AddTodo onAdd={this.addToDo}></AddTodo> we are actually declaring a prop — onAdd. Because as I told you in the previous article that props are used for component communication. And in our case, original todos array is in parent component and new update array is on child component so.

Now finally time to run this app and add some items.

Now it’s time to move on our last article of this series that is Part-5 where we will Deploy this ToDo Application to Github pages..!!

Jinal Shah is corporate trainer on different technology like node.Js, Angular,Ionic 2, BOT Framework etc.