DEV Community

yousef shallah
yousef shallah

Posted on

Create a simple TODO reactjs app

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
 }
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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
      }
    ]);
  }
Enter fullscreen mode Exit fullscreen mode

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);
   };
Enter fullscreen mode Exit fullscreen mode

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);
  };
Enter fullscreen mode Exit fullscreen mode

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);
  };
Enter fullscreen mode Exit fullscreen mode

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>
  );
Enter fullscreen mode Exit fullscreen mode

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>
   );
 }
Enter fullscreen mode Exit fullscreen mode

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>
       );
      }
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

now you can run todo app:

npm start
Enter fullscreen mode Exit fullscreen mode

Discussion (0)