Let’s build a simple Todo App with React which teaches you the basic principles of CRUD (Create, Read, Update and Delete)
Hello readers! This is the first time I am writing an article on building something with React. Building a Todo App is easy and does not take much time but it teaches you some important concepts in reactjs. It teaches you the principle of CRUD (Create, Read, Update and Delete) which are very important to understand for any developer.
Building a simple Todo list means we won’t be able to keep track of the todos once we refresh the page. So, it is not a perfect solution but a good start.
We will learn to build an advanced Todo App which would involve Redux and a server but for now, we would like to keep things simple.
let’s begin...
So, let’s start building our first React Todo app
npx create-react-app todo
Now, this would create a folder named ‘todo’ in our current repository. Next, we should move inside the todo folder by
cd todo
Now, we will install libraries we need using npm which would help us with using the Bootstrap library to apply the styling.
npm install react-bootstrap bootstrap
Running the above command will install both react-bootstrap and bootstrap packges in todo app.
Now, we are ready to build the app.
App.css
Now, let’s write some custom CSS code to do some styling
.app {
padding: 30px;
background-color: #848586;
}
.todo {
display: flex;
align-items: center;
font-size: 18px;
justify-content: space-between;
}
App.js
Next, We will start by import the required things in our App.js file.
import React, {useState, useEffect} from "react";
import { Button, Card, Form } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import "./App.css";
We will use React Hooks.
So, we start with the main Todo function of the App.
We will define a todos list which would contain all our todos and also carries the status of each todo whether they are done or not. We will use setTodos and will use useState hook.
const App = () => {
const [todos, setTodos] = useState([
{
label: "This is a sampe todo",
isDone: false
}
]);
}
Next, we move to the part of adding todos. We will define an addTodo function and will define a newTodos which would take the todos list and append the new todo’s label to the list. We then use setTodos to set newTodos as todos.
const addTodo = (label) => {
const newTodos = [...todos, { label }];
setTodos(newTodos);
};
Next, we move to the part of marking Todos as done. We will define a markTodo function. We use the spread operator to copy all the todos in newTodos and then we mark the todo as done by using its index and then we set the newTodos as todos.
const markTodo = index => {
const newTodos = [...todos];
newTodos[index].isDone = true;
setTodos(newTodos);
};
Next, we move the part of deleting the todos. In the same way, this time we use the index to splice the list and remove the todo whose index matches and then we set the new todos.
Next, we move the part of deleting the todos. this time we use the index to splice the list and remove the todo whose index matches and then we set the new todos.
const removeTodo = index => {
const newTodos = [...todos];
newTodos.splice(index, 1);
setTodos(newTodos);
};
We then finish off the App functions. We are using a FormTodo component which we will define later on. It accepts the addTodo as a parameter.
Then we display all the todos list. and get every todo and we will pass it to the Todo component. We send the index, todo, the markTodo and removeTodo functions.
return (
<div className="app">
<div className="container">
<h1 className="text-center mb-4">Todo List</h1>
<FormTodo addTodo={addTodo} />
<div>
{todos.map((todo, index) => (
<Card>
<Card.Body>
<Todo
key={index}
index={index}
todo={todo}
markTodo={markTodo}
removeTodo={removeTodo}
/>
</Card.Body>
</Card>
))}
</div>
</div>
</div>
);
Now, we will define the Todo component. It accepts parameters which we passed on earlier when we called the Todo component.
We return some JSX which would show each Todo. It will also show two buttons for marking Todos as Done and for removing the Todo respectively.
const Todo = ({ todo, index, markTodo, removeTodo }) ={
return (
<div className="todo" >
<span style={{ textDecoration: todo.isDone ? "line- through" : "" }}>{todo.label}</span>
<div>
<Button variant="outline-success" onClick={() =>
markTodo(index)}>✓</Button>{' '}
<Button variant="outline-danger" onClick={() =>
removeTodo(index)}>✕</Button>
</div>
</div>
);
}
Next, we would define the FormTodo function. It accepts the addTodo as a parameter. It handles the submission of a new Todo. If the value is not empty, then we call the addTodo function on that todo text and then set the value of the form to empty again.
We return a form which accepts a Todo and has a Submit button for submission of the todos. Clicking on the submit button would add the Todo in the Todo list.
const FormTodo = ({ addTodo }) => {
const [value, setValue] = useState("");
const handleSubmit = e => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<Form onSubmit={handleSubmit}>
<Form.Group>
<Form.Label><b>Add Todo</b></Form.Label>
<Form.Control type="text" className="input" value=
{value} onChange={e => setValue(e.target.value)}
placeholder="Add new todo" />
</Form.Group>
<Button variant="primary mb-3" type="submit">
Submit
</Button>
</Form>
);
}
Now, let’s look at App.js file:
import React, {useState, useEffect} from "react";
import { Button, Card, Form } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import "./App.css";
const Todo = ({ todo, index, markTodo, removeTodo })
=> {
return (
<div className="todo">
<span style={{ textDecoration: todo.isDone ? "line-
through" : "" }}>{todo.label}</span>
<div>
<Button variant="outline-success" onClick={() =>
markTodo(index)}>✓</Button>{' '}
<Button variant="outline-danger" onClick={() =>
removeTodo(index)}>✕</Button>
</div>
</div>
);
}
const FormTodo = ({ addTodo }) => {
const [value, setValue] = useState("");
const handleSubmit = e => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<Form onSubmit={handleSubmit}>
<Form.Group>
<Form.Label><b>Add Todo</b></Form.Label>
<Form.Control type="text" className="input" value=
{value} onChange={e => setValue(e.target.value)}
placeholder="Add new todo" />
</Form.Group>
<Button variant="primary mb-3" type="submit">
Submit
</Button>
</Form>
);
}
const App = () => {
const [todos, setTodos] = useState([
{
label: "This is a sampe todo",
isDone: false
}
]);
const addTodo = label => {
const newTodos = [...todos, { label }];
setTodos(newTodos);
};
const markTodo = index => {
const newTodos = [...todos];
newTodos[index].isDone = true;
setTodos(newTodos);
};
const removeTodo = index => {
const newTodos = [...todos];
newTodos.splice(index, 1);
setTodos(newTodos);
};
return (
<div className="app">
<div className="container">
<h1 className="text-center mb-4">Todo List</h1>
<FormTodo addTodo={addTodo} />
<div>
{todos.map((todo, index) => (
<Card>
<Card.Body>
<Todo
key={index}
index={index}
todo={todo}
markTodo={markTodo}
removeTodo={removeTodo}
/>
</Card.Body>
</Card>
))}
</div>
</div>
</div>
);
}
export default App;
now you can run todo app:
npm start
Top comments (0)