Building a To-Do List App Using React - Hooks and Styled Component
Tags: react, beginners, webdev, tutorial
Published: 2022-06-05 16:42:18

![image.png](https://miro.medium.com/proxy/0*OZXZ-kMRjX_2MOdI)

### Introduction
Hooks were introduced in React 16.8. They allow use of state and other React features by using functional components. There are various types of hooks available in React for example **useState**, **useEffect**, **useContext** among others. For To-do List project we will only be using useState hook. 
**useState**- allows adding of state to functional component.
**Styled-component** on the other hand is a popular library that is used to style react applications. It allows writing actual CSS in your JavaScript. You can find out more on [All you need to know about styled-components with React](https://dev.to/tndungu/styled-components-in-react-all-you-need-to-know-4c82).

If you would prefer to follow this tutorial on YouTube its available at the link below.

{% youtube YTL99dkidzU %}

A complete working solution is available on Github 
{% github https://github.com/tndungu/TodoListApp %}

### To Do App
The To Do App that we are going to build will allow a user to add a task to a list of to-do items. Once the task is added, the user will be able to mark it as completed once its done. When you click on a task, if it was pending it will be marked as complete by crossing the task with a line. There will be a count that will be displaying both the pending and completed tasks.

<img width="80%" style="width:80%" src="https://media0.giphy.com/media/NyzUiZKe19QJyMrPtb/giphy.gif?cid=790b76117d693ca8aba5089f186ff7c10195dfbbf1541117&rid=giphy.gif&ct=g">

### Step by Step Guide
**1. Create a React App**
- **yarn**:
```TypeScript
yarn create react-app todo-list
```
- **npm**:
```TypeScript
npx create-react-app todo-list
```

cd into todo-list and `yarn start` OR `npm start` if using npm. 

**2. Design the UI**

In the src folder, open `App.js` and get rid of everything between <div> tags. The `App.js` file should look as below:
```TypeScript
import React from 'react';
import './App.css';
 
function App() {
 return (
   <div className="App">
    	Hello World! Starting a to-do List
   </div>
 );
}
 
export default App;
```

We will use styled-components for styling our App. Using the following command install the styled-component package.

```TypeScript
npm install styled-components
```

import the styled-components in our App.js by adding the following in import section.

```TypeScript
import styled from "styled-components";
```

Our first component will be **Container** div with styling done using styled component. Our App will now look as follows.

```TypeScript
import React from 'react';
import './App.css';
import styled from "styled-components";

const Container = styled.div`
  display: flex;
  align-items: center;
  flex-direction: column;
`;

function App() {
 return (
   <Container>
   </Container>
 );
}
 
export default App;
```

**3. Complete the UI**

Other components which includes input, button, span, div will be styled using styled-components and we will end up with the following for our UI definition. Our UI definition will be completed at this point. 

```TypeScript
import React from 'react';
import './App.css';
import styled from "styled-components";

const Container = styled.div`
  display: flex;
  align-items: center;
  flex-direction: column;
`;

const Button = styled.button`
  display:inline-block;
  flex: 1;
  border: none;
  background-color: teal;
  color: white;
  height: 30px;
  width: 50px;
  border-radius: 2px;
  cursor: pointer;
`;

const Text = styled.input`
  border: 2px solid #000;

`;

const TaskCount = styled.span`
  margin: 10px;
`;

const Tasks = styled.div`
`;

const TaskCount = styled.span`
  margin: 10px;
`;

const Tasks = styled.div`
`;

function App() {
 return (
  <Container>
      <div>
          <h2>Todo List</h2>
          <Text value={input} />
          <Button>Add</Button>
        <Tasks>
          <TaskCount>
            <b>Pending Tasks</b> 
          </TaskCount>
          <TaskCount>
            <b>Completed Tasks</b>
          </TaskCount>
        </Tasks>
        <div>
          <ul>
              /* List items consisting of tasks will be listed here */
          </ul>
        </div>
        <Button>Clear</Button>
      </div>
    </Container>
 );
}
 
export default App;
```
**4. Add Tasks and Mark Completed tasks**

At this point the UI is completed. We need to add functionality which will enable a user to add new tasks and mark completed tasks.

We will use useState() hook that will store the state. In our imports we add the following:
```TypeScript
import React, { useState } from "react";
```

Using useState() hook, we will initialize the following states which will store state and manage changes to the variables.
input - variable to keep track of the task user inputs.
todoList - will consist of an array that will have a list of all tasks. Each task is defined as an object which looks as follows:
```TypeScript
{
     id: id, //unique id
     task: Task, // a task to be added to the todo list
     complete: false, //false means task is incomplete, true means task is completed
 }
```
completedTaskCount - will keep track of count of completed tasks.

inside the App function in App.js, we will add the following:

```TypeScript
const [input, setInput] = useState("");
const [todoList, setTodoList] = useState([]);
const [completedTaskCount, setCompletedTaskCount] = useState(0);
```

In the Text and Button components, we will add event handler functions `setInput()` and `handleClick()`. The `setInput()` will set value of user task input while `handleClick()` will add the task to todoList.

```TypeScript
<Text value={input} onInput={(e) =>setInput(e.target.value)} />
<Button onClick={() => handleClick()}>Add</Button>
```

handleClick() function:

```TypeScript
const handleClick = () => {
  const id = todoList.length + 1;
  setTodoList((prev) => [
    ...prev,
    {
      id: id,
      task: input,
      complete: false,
    },
  ]);
  setInput("");
};
```

**5. Display List of tasks**

Inside the **ul** tag we will define a map function that will iterate through the todoList [] array and create **li** list items for display. Each list item(task) will contain properties which includes: id, complete, onClick() event handler and task. It will look as follows:

   ```TypeScript
<ul>
  {todoList.map((todo) => {
    return (
      <LIST
        complete={todo.complete}
        id={todo.id}
        onClick={() => handleComplete(todo.id)}
        style={{
          listStyle: "none",
          textDecoration: todo.complete && "line-through",
        }}
      >
        {todo.task}
      </LIST>
    );
  })}
</ul>;
```

The `textDecoration`style will conditionally apply a line-through for completed tasks and pending tasks will not have a line-through. On clicking the **Add** button, `handleComplete(id)` function will be called and it will do the following.

- Modify the complete property of a task object to true or false depending on the previous state. 
- Increment/decrement the completedTaskCount variable depending if the complete property changed to true or false.

The function definition will be as follows:
```TypeScript
const handleComplete = (id) => {
    let list = todoList.map((task) => {
      let item = {};
      if (task.id == id) {
        if (!task.complete){
            //Task is pending, modifying it to complete and increment the count
            setCompletedTaskCount(completedTaskCount + 1);
        } 
        else {
            //Task is complete, modifying it back to pending, decrement Complete count
            setCompletedTaskCount(completedTaskCount - 1);
        }

        item = { ...task, complete: !task.complete };
      } else item = { ...task };

      return item;
    });
    setTodoList(list);
  };
```

**6. Final ToDo List**
The final ToDo List code will look as below. Note that all along we have been modifying the `App.js` file only.

```TypeScript
import { useState } from "react";
import styled from "styled-components";
import "./index.css";

const Container = styled.div`
  display: flex;
  align-items: center;
  flex-direction: column;
`;

const Button = styled.button`
  display:inline-block;
  flex: 1;
  border: none;
  background-color: teal;
  color: white;
  height: 30px;
  width: 50px;
  border-radius: 2px;
  cursor: pointer;
`;

const Text = styled.input`
  border: 2px solid #000;
  width: 200px;
  padding: 5px;
  border-radius: 2px;
  margin: 5px;
`;

const TaskCount = styled.span`
  margin: 10px;
`;

const Tasks = styled.div`
`;

const LIST = styled.li`
    listStyle:"none";
    text-decoration: "line-through";
`;

const App = () => {
  const [input, setInput] = useState("");
  const [completedTaskCount, setCompletedTaskCount] = useState(0);
  const [todoList, setTodoList] = useState([]);

  const handleClick = () => {
    const id = todoList.length + 1;
    setTodoList((prev) => [
      ...prev,
      {
        id: id,
        task: input,
        complete: false,
      }
    ]);
    setInput("");
  };
  const handleComplete = (id) => {
    let list = todoList.map((task) => {
      let item = {};
      if (task.id == id) {
        if (!task.complete){
            //Task is pending, modifying it to complete and increment the count
            setCompletedTaskCount(completedTaskCount + 1);
        } 
        else {
            //Task is complete, modifying it back to pending, decrement Complete count
            setCompletedTaskCount(completedTaskCount - 1);
        }

        item = { ...task, complete: !task.complete };
      } else item = { ...task };

      return item;
    });
    setTodoList(list);
  };

  return (
    <Container>
      <div>
          <h2>Todo List</h2>
          <Text value={input} onInput={(e) =>setInput(e.target.value)} />
          <Button onClick={() => handleClick()}>Add</Button>
        <Tasks>
          <TaskCount>
            <b>Pending Tasks</b> {todoList.length - completedTaskCount}
          </TaskCount>
          <TaskCount>
            <b>Completed Tasks</b> {completedTaskCount}
          </TaskCount>
        </Tasks>
        <div>
          <ul>
            {todoList.map((todo) => {
              return (
                <LIST
                  complete = {todo.complete}
                  id={todo.id}
                  onClick={() => handleComplete(todo.id)}
                  style={{
                    listStyle: "none",
                    textDecoration: todo.complete && "line-through",
                  }}
                >
                  {todo.task}
                </LIST>
              );
            })}
          </ul>
        </div>
      </div>
    </Container>
  );
};

export default App;
```

### Conclusion

Congratulations! You have now built a To do list App using React hooks and styled-components. You have also gone through other aspects of React and ES6 JavaScript. Its quite straight forward to develop. The above boilerplate can be used to extend the App to include more functionalities around the App. You can do the following if you would like to learn more.
- Once task is completed, instead of strike-through you can make it to disappear.
- Add a button below the list of tasks called "**Clear**" that when clicked it clears all the tasks.

Feel free to comment below incase you need further assistance.