Todo list utilizando Context API
Tags: react, usecontext
Published: 2021-01-29 15:07:38

[Acessar demo](https://marina-santana.github.io/todo-list-context-api/)

A ideia por trás deste tutorial é ensinar como utilizar o Context API para facilitar o desenvolvimento da sua aplicação react e evitar em alguns casos a utilização do redux, para gerenciamentos simples de estados globais.

![todo list](https://dev-to-uploads.s3.amazonaws.com/i/lfs43r9251zfseh5kh8m.gif)

### **Context**
O context é o responsável por gerenciar os estados globais da nossa aplicação, nele ficará o estado a ser compartilhado pelos componentes e os métodos utilizados por eles, nesse caso temos apenas um estado a ser compartilhado, que é o todos e os métodos relacionados a ele são, inserção, atualização e exclusão.

No **TodoProvider** ficam armazenados o estado e métodos que devem ser compartilhados entre os componentes, ele recebe o parâmetro children, que são os componentes filhos que vão poder consumir tudo que foi declarado dentro dele.

```javascript
import React, { useState, createContext } from "react";

export const TodoContext = createContext();

const TodoProvider = ({ children }) => {
  const [todos, setTodos] = useState([
    { id: 1, title: "Estudar react", done: true },
    { id: 2, title: "Estudar webpack", done: false },
    { id: 3, title: "Estudar context", done: false },
    { id: 4, title: "Estudar redux", done: false },
  ]);

  const saveTodo = (todo) => {
    const newTodo = {
      id: todo.length + 1,
      title: todo.title,
      done: false,
    };

    setTodos([...todos, newTodo]);
  };

  const removeTodo = (todoIndex) => {
    todos.splice(todoIndex, 1);

    setTodos([...todos]);
  };

  const checkTodo = (todoIndex) => {
    const todo = todos[todoIndex];
    todo.done = !todo.done;

    setTodos([...todos]);
  };

  return (
    <TodoContext.Provider value={{ todos, saveTodo, checkTodo, removeTodo }}>
      {children}
    </TodoContext.Provider>
  );
};

export default TodoProvider;
```

### **Componente do formulário**

O componente do formulário é responsável para criação de um novo todo, ele consome o método **saveTodo** do context.

```javascript
import React, { useContext, useState } from "react";
import { TodoContext } from "../context/TodoContext";

const TodoForm = () => {
  const { saveTodo } = useContext(TodoContext);
  const [todo, setTodo] = useState();

  const handleSubmit = (event) => {
    event.preventDefault();
    saveTodo(todo);
    event.target.reset();
  };

  const handleInputChange = (event) => {
    setTodo({
      ...todo,
      title: event.target.value,
    });
  };

  return (
    <form onSubmit={handleSubmit} className="form-inline">
      <div>
        <input
          type="text"
          name="title"
          className="form-control"
          placeholder="Nova tarefa"
          onChange={handleInputChange}
        />
        <button type="submit" className="btn btn-default" />
      </div>
    </form>
  );
};

export default TodoForm;
```
### **Componente da lista**

O componente da lista será responsável por exibir os dados que estão salvos no estado e também por atualizar e excluir algum item da lista, para exibição ele utiliza o **map** que é um recurso do próprio javascript, já para a exclusão e atualização ele utiliza os métodos removeTodo e checkTodo eles são importados do context.

```javascript
import React, { useContext } from "react";
import { TodoContext } from "../context/TodoContext";

function TodoList() {
  const { todos, removeTodo, checkTodo } = useContext(TodoContext);

  const handleDelete = (todoIndex) => {
    removeTodo(todoIndex);
  };

  const handleDone = (todoIndex) => {
    checkTodo(todoIndex);
  };

  return (
    <ul>
      {todos.map((todo, index) => (
        <li className="list-group-item" key={index}>
          <div className={todo.done ? "done" : "undone"}>
            <span className="icon" onClick={() => handleDone(index)}></span>
            <span>{todo.title}</span>
            <button
              type="button"
              className="close"
              onClick={() => handleDelete(index)}
            >
              &times;
            </button>
          </div>
        </li>
      ))}
    </ul>
  );
}

export default TodoList;
```
### **Integração do context com os componentes**

Por fim, é necessário fazer a integração dos componentes com o context, esse passo é o mais simples, importamos o nosso provider e colocamos os componentes que compartilham o mesmo estado dentro dele, depois disso todos esses componentes têm acesso ao estado e aos métodos que foram declarados no context.

```javascript
import React from "react";
import TodoProvider from "./context/TodoContext";
import TodoForm from "./components/TodoForm";
import TodoList from "./components/TodoList";
import "./style.css";

const App = () => {
  return (
    <TodoProvider>
      <div className="todoForm">
        <h3 className="title">Lista de tarefas</h3>
        <TodoForm />
        <TodoList />
      </div>
    </TodoProvider>
  );
};

export default App;
```

**Obs:** Em aplicações mais complexas onde se tem a necessidade de gerenciar muitos estados de diferentes maneiras, é mais recomendado se utilizar o redux ao invés de context api.

**Repositório**
[Todo List 👩🏿‍💻](https://github.com/marina-santana/todo-list-context-api)