Hello today we are going to build a todo list app in react by which you can understand basics of react how it works
we can use code sandbox CodeSandbox here to get started with react it provides an template to build our web apps faster.
To start with your todo app create a new sandbox by selecting react template.
After creating an sandbox react-template checkout how files are organized in react and this structure is going to be common in react.
App.js
import "./styles.css";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
For our todo list application all our code is to be done in app.js.
So Let's Get Started...
1) Adding Input Element to our App
App.js
import "./styles.css";
export default function App() {
return (
<div className="App">
// heading
<div className="heading">
<h1>TO-DO App</h1>
</div>
// form element to take input from user
<form className="formtodo">
<input placeholder="Enter Your Text Here..."
type="text"
id="todoValue"
></input>
<button type="submit">Add Todo</button>
</form>
</div>
);
}
2) Adding onChange and onSubmit to input
App.js
import "./styles.css";
export default function App() {
function handleSubmit(){
// event handler function
}
function changeHandler(e){
// event handler function
}
return (
<div className="App">
// heading
<div className="heading">
<h1>TO-DO App</h1>
</div>
// form element to take input from user
// adding onSubmit and onChange event listener.
<form className="formtodo" onSubmit={handleSubmit}>
<input
onChange={changeHandler}
placeholder="Enter Your Text Here..."
type="text"
id="todoValue"
></input>
<button type="submit">Add Todo</button>
</form>
</div>
);
}
Here we have declared two event listener method onChange and onSubmit to handle user input and these event listener method will call event handler functions to further process the input of user.
3) Adding useState hook
What is a hook? hook is an special function which allow us to add and update state variables.so here we are going to use useState hook to store and update our list of tasks.
App.js
import "./styles.css";
import {useState} from 'react';
export default function App() {
const [todoValue, setTodoValue] = useState('');
const [todos, settodos] = useState([]);
function handleSubmit(event){
// event handler function
event.preventDefault(); // this will prevent default behaviour of form on submit
}
function changeHandler(event){
// event handler function
setTodoValue(event.target.value);
}
return (
<div className="App">
// heading
<div className="heading">
<h1>TO-DO App</h1>
</div>
// form element to take input from user
// adding onSubmit and onChange event listener.
<form className="formtodo" onSubmit={handleSubmit}>
<input
onChange={changeHandler}
placeholder="Enter Your Text Here..."
type="text"
id="todoValue"
></input>
<button type="submit">Add Todo</button>
</form>
</div>
);
}
We are taking current input value by (event.target.value) and assigning that current input value to state variable (setTodoValue) in changeHandler function
4) Add Task
App.js
import "./styles.css";
import {useState} from 'react';
export default function App() {
const [todoValue, setTodoValue] = useState('');
const [todos, settodos] = useState([]);
function handleSubmit(event){
// event handler function
event.preventDefault(); // this will prevent default behaviour of form on submit
if (todoValue === undefined ||
todoValue === "" ||
todoValue?.trim() === ""){
alert("You are lazy!!! enter proper value.");
}else {
const todo = {
value: todoValue,
done: false
};
// spreading of previous value of todos
settodos([...todos, todo]);
document.getElementById("todoValue").value = "";
// console.log(todoValue);
settodoValue("");
// console.log(todoValue)
}
}
function changeHandler(event){
// event handler function
setTodoValue(event.target.value);
}
return (
<div className="App">
// heading
<div className="heading">
<h1>TO-DO App</h1>
</div>
// form element to take input from user
// adding onSubmit and onChange event listener.
<form className="formtodo" onSubmit={handleSubmit}>
<input
onChange={changeHandler}
placeholder="Enter Your Text Here..."
type="text"
id="todoValue"
></input>
<button type="submit">Add Todo</button>
</form>
<div className="output">
{todos &&
todos.map((task, i) => {
return (
<div className="todo-list" key={task.value} id={i}>
<button>
{task.value}
</button>
</div>
);
})}
</div>
</div>
);
}
we are taking input value by (event.target.value) and assigning that value to state variable(setTodoValue(e.target.value)).on submit of task handleSubmit function will be called and will check for blank values if not then it will make an object of keys(value,done)in else block of handleSubmit function and add that to state array using settodos([...todos,todo])spreading of array method.
For displaying our task-list mapping of todos array is done.
for other operation like line-through and delete we need to access the index {i} while mapping through todos array.
5)Delete Task and line-through it
App.js
import "./styles.css";
import { useState } from "react";
export default function App() {
const [todoValue, settodoValue] = useState("");
const [todos, settodos] = useState([]);
const handleDone = (e) => {
const { id } = e.target.parentElement;
todos[id].done = !todos[id].done;
// console.log(todos[id].done, todos[id].value);
settodos([...todos]);
};
function handleSubmit(e) {
e.preventDefault();
if (
// todoValue === <strong>[‏‏‎]</strong> ||
// todoValue?.trim() == " " ||
todoValue === undefined ||
todoValue === "" ||
todoValue?.trim() === ""
) {
alert("You are lazy!!! enter proper value.");
} else {
const todo = {
value: todoValue,
done: false
};
// spreading of previous value of todos
settodos([...todos, todo]);
document.getElementById("todoValue").value = "";
// console.log(todoValue);
settodoValue("");
// console.log(todoValue)
}
}
function hanleDelete(e) {
const { id } = e.target.parentElement;
console.log(id);
console.log(e.target.parentElement);
todos.splice(id, 1);
settodos([...todos]);
}
function changeHandler(event) {
settodoValue(event.target.value);
// console.log(event.target.value);
}
return (
<div className="App">
<div className="heading">
<h1>TO-DO App</h1>
</div>
<div>
<form className="formtodo" onSubmit={handleSubmit}>
<input
placeholder="Enter Your Text Here..."
type="text"
id="todoValue"
onChange={changeHandler}
></input>
<button type="submit">Add Todo</button>
</form>
</div>
<div>
{todos &&
todos.map((task, i) => {
return (
<div className="todo-list" key={task.value} id={i}>
<button
// if task.done is true then apply "done" to classname else apply "not-done".. task.done will be changed to true on click over it
className={task.done ? "done" : "not-done"}
onClick={handleDone}
>
{task.value}
</button>
{/* {task.value} */}
<button onClick={hanleDelete}>Delete</button>
</div>
);
})}
</div>
</div>
);
}
For Delete operation on click button will call handle delete and this event handler function takes task id and it uses splice method to remove that cliked {id} Task from the array and it updates the todos array after splice method.
For line-through operation on click button will call handleDone and in that function it will toggle the key "done:false" to its opposite value"done:true" and reset that change "done" value to todo array by settodos([...todos]).for this operation we have defined conditional className and used css line-through property.
Style.css
@import url("https://fonts.googleapis.com/css?family=Roboto+Condensed:300i,400,400i,700");
* {
padding: 0;
margin: 0;
}
.heading {
color: #332d36;
font-weight: 300;
font-size: 2.5rem;
text-align: center;
}
body {
background: skyblue;
}
.App {
font-family: sans-serif;
text-align: center;
/* background: skyblue; */
padding: 1rem;
font-family: "Roboto Condensed", sans-serif;
}
button,
input {
all: unset;
color: blue;
-webkit-text-fill-color: blue;
cursor: pointer;
}
.done {
text-decoration: line-through;
}
input {
padding: 1rem;
border-radius: 5px;
text-align: left;
cursor: text;
background: whitesmoke;
/* outline-width: 0.1rem; */
box-shadow: 1px 2px 5px 1px;
}
[type="submit"] {
padding: 1rem;
margin-left: 0.5rem;
background: whitesmoke;
border-radius: 10px;
box-shadow: 1px 4px 1px 1px;
}
[type="submit"]:active {
box-shadow: 1px 2px 1px 1px;
}
.todo-list {
background: wheat;
padding: 1rem;
margin: 1rem auto;
border-radius: 10px;
max-width: 500px;
width: 100%;
/* overflow: scroll; */
display: grid;
grid-template-columns: 4fr 1fr;
}
.formtodo {
/* background: whitesmoke; */
padding: 1rem;
margin: 1rem auto;
max-width: 550px;
display: grid;
grid-template-columns: 4fr 1fr;
}
.not-done,
.done {
border-radius: 10px 0 0 10px;
border: none;
text-align: left;
padding: 1rem;
}
So that's complete our todo list app , sharing my codesandbox link for your reference.
Top comments (2)
Nice
Glad you liked it 🙏🙏 thank you 😊