React todo app using useState
Tags: react
Published: 2023-02-09 08:53:27

Hello Developers

Today we are going to create a simple to-do app with add/edit and delete feature using react.

I have used pnpm for dependencies instead of npm. Bootstrap, react-bootstrap for CSS. UUID for unique ids. Here is the folder structure for project.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jpl52o38kxaqiu2odq9.png)

First we need to create project.

```
pnpm create vite@latest
```

Above command will show options to create react app. Select for react js app and crete new folder. Then goto new created folder and run "pnpm install" and "pnpm add react react-bootstrap uuid" commands. New project setup and ready to use for next changes.


Next, in app.js, update it with following code.

```
import { useState } from 'react'
import './App.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import Todo from './components/todo/Todo'
import { Container } from 'react-bootstrap'

function App() {
  const [count, setCount] = useState(0)

  return (
    <div className="App mt-3">
      
      <Container>
      <h1>Add/Edit/Delete todo example using state</h1>
      <Todo/>      
      </Container>
    </div>
  )
}

export default App
```
Next we need to create new folder/files as per folder structure image. In components/todo folder, create Todo.jsx with following code.

```
import React from 'react'
import TodoForm from './TodoForm'
import TodoList from './TodoList'
import { Row, Col } from 'react-bootstrap'
import { useEffect } from 'react';
import { useState } from 'react'
import {v4 as uuidv4} from "uuid";
const Todo = () => {
    const items = [
        { id:uuidv4(), title: 'Item 1' },
        { id: uuidv4(), title: 'Item 2' }
    ];

    const [todos, setTodo] = useState([]);
    const [editItem, setEditItem] = useState(null);
    useEffect(() => {        
        setTodo(items);
    },[]);
    const handleRemoveTodo = (id) => {
        /*const itemToDelete = todos.findIndex(element => {
            return element.id === id;
        });
        const newItems = todos.splice(itemToDelete, 1);*/

        const newItems = todos.filter(item => item.id !== id);
        setTodo([...newItems]);
        //console.log(todos);
    }

    const handleAddTodo = (form) => {        
        setTodo([...todos, {id: uuidv4(), title:form.title}]);        
    }

    const handleEditTodo = (item) => {
        setEditItem(item);
    }

    const handleSubmitEditForm = (form) => {
        const indexItemToUpdate = todos.findIndex(item =>  item.id == form.id);
        //console.log(indexItemToUpdate);
        const newArr = todos.map(item => {
            if(item.id == form.id){
                item.title = form.title;
            }
            return item;
        });
        setTodo([...newArr]);
        setEditItem(null);
    }
    return (
        <div className=''>
            <Row>
                <Col xs={4}>
                    <TodoForm editItem={editItem}
                    handleAddTodo={handleAddTodo}
                    handleEditTodo={handleEditTodo}
                    handleSubmitEditForm={handleSubmitEditForm}
                    />
                </Col>
                <Col>
                    <TodoList
                        todos={todos}                        
                        handleRemoveTodo={handleRemoveTodo}
                        handleEditTodo={handleEditTodo}
                         />
                </Col>
            </Row>


        </div>
    )
}

export default Todo
```
Next we need to create todo list components. Create new file in components/todo folder named TodoList.jsx and add following code.

```
import React from 'react'
import { Row, Col } from 'react-bootstrap'
import { Button } from 'react-bootstrap'

const TodoList = ({ todos, handleRemoveTodo, handleEditTodo }) => {
    return (
        <div className='card'>
            <div className='card-body'>
                {todos?.length > 0 ? (
                    <>
                        {todos.map(item => (
                            <div className='row mb-1'>
                                <div className='col-8'>
                                    {item.title}
                                </div>
                                <div className='col-1'>
                                    <Button onClick={() => handleEditTodo(item)}>edit</Button>
                                </div>
                                <div className='col-2'>
                                    <Button className="ms-2" onClick={() => handleRemoveTodo(item.id)}>x</Button>
                                </div>
                            </div>
                        ))}
                    </>
                ) : 'No todo to display'}
            </div>
        </div>
    )
}

export default TodoList
```
So we have created list for todo component, next we need to create form component where we can add/edit todos. Create new file in components/todo named TodoForm.jsx with following code.

```
import React from 'react'
import { useEffect } from 'react';
import { useState } from 'react'

const TodoForm = ({ editItem, handleAddTodo, handleEditTodo, handleSubmitEditForm }) => {
  const [form, setForm] = useState({
    id: null,
    title: ""
  });
  useEffect(() => {
    if (editItem !== null) {
      setForm({ id: editItem.id, title: editItem.title });
    }
  }, [editItem])
  const handleSubmitForm = () => {
    if (form.id !== null) {
      handleSubmitEditForm(form);
    } else {
      handleAddTodo(form);
    }
    setForm(prev => ({ title: "", id: null }));
  }

  const handleFormChange = (e) => {
    setForm({
      ...form,
      [e.target.id]: e.target.value
    });
  }
  return (
    <div className='card'>
            <div className='card-body'>
      {editItem !== null ?
        <div className='row'>
          <div className='col-12'>
            <input className='form-control' placeholder='Title' id="title" type="text" value={form.title} onChange={(e) => handleFormChange(e)} />
          </div>
          <div className='col-12 mt-1'>
            <button className='btn btn-primary' onClick={() => handleSubmitForm(form)}>Save</button>
          </div>
        </div>
        :
        <div className='row'>
          <div className='col-12'>
            <input className='form-control' placeholder='Title' id="title" type="text" value={form.title} onChange={(e) => handleFormChange(e)} />
          </div>
          <div className='col-12 mt-1'>
            <button className='btn btn-primary' onClick={() => handleSubmitForm(form)}>Add</button>
          </div>
        </div>
      }

    </div>
    </div>
  )
}

export default TodoForm
```
That's it. Our todo app is ready to use. Start your server and see it in action.

Happy Coding :)