4 de novembro de 2019 às 15:30

Implementando adicionar e remover itens de listas em tempo de execução.

Tempo de leitura: 5 minutos

Fala galera! depois de algum tempo sem postar, eu estou de volta!

Dessa vez vou falar sobre a implementação de listas dinâmicas utilizando o ReactJS, o termo lista dinâmica vai ser muito usado neste post, então vou começar definindo-o:

Uma lista dinâmica como o nome diz é uma lista que pode ser alterada pelo usuário, podemos concretizar o termo com uma lista de tarefas, onde cada tarefa possui nome e data e o usuário pode adicionar ou remover tarefas, sem afetar os outros itens da lista;

Diferente das outras vezes, vou utilizar create-react-app, vou prezar pela simplicidade e não vou utilizar outras bibliotecas nem mesmo styled-components, mas caso você vá utilizar o react em uma aplicação maior, recomendo que utilize React com webpack e styled-components.

Pré requisitos e conhecimentos prévios desejáveis:

Estou considerando neste post que você já sabe sobre layout e, também, como criar um projeto em React-Native, dito isto, será ignorada toda a parte de criação e configuração do projeto.

  • ReactJS
  • Layout com FlexBox
  • Arrays com JavaScript

Primeiro vamos criar e executar o projeto com:

$ npx create-react-app dynamic-list-itens
$ yarn start

Criando os componentes

Em seguida vamos criar um componente que irá servir para exibir cada item na lista, vou ignorar todo o css no artigo, mas você pode pegar o css a partir do repositório no final do artigo.

import React from 'react';

const ListItem = ({ onChange, onDelete, value }) => {
  return (
    <div className="Item-container">
      <input
        className="Item-field"
        value={value}
        onChange={onChange}
      />
      <button onClick={onDelete}>Excluir</button>
    </div>
  );
};

export default ListItem;

Basicamente este componente precisará disparar dois eventos para o elemento pai: o evento de edição e o evento de exclusão, para isso criei duas props: onChange e onDelete, também uma prop para receber o nome atual da tarefa: value. De resto é um componente bem simples.

Agora vamos criar um novo componente responsável pela criação de novas tarefas:

import React, { useState } from 'react';
const NewTaskInput = ({ onSubmit }) => {

  const [newItem, setNewItem] = useState('');

  function setNewTask({target}) {
    setNewItem(target.value);
  }

  function submit(e) {
    e.preventDefault();
    onSubmit(newItem);
  }

  return (
    <div>
      <form onSubmit={submit}>
        <input
          className="Todo-input"
          placeholder="Digite uma nova tarefa"
          onChange={setNewTask}
        />
        <button type="submit">
          Adicionar
        </button>
      </form>
    </div>
  )
};

export default NewTaskInput;

Outro componente bem simples, esse irá disparar apenas um evento para o elemento pai: o evento para adicionar a nova tarefa. Esse componente mantém um estado interno com o valor do input e repassa esse valor através do evento onSubmit. Note que usei um form, fiz isso para que seja possível adicionar a tarefa pressionando enter. note também que na função submit eu estou chamando o preventDefault do disparo do form, para impedir que a página seja recarregada após o envio.

Vamos agora à criação do Component que irá conter o que acabamos de criar, esse componente será o responsável por manter o array que irá conter as tarefas, exclusão de uma tarefa e por atualizar uma tarefa também.

import React, { useState } from 'react';
import './App.css';
import ListItem from './components/ListItem'
import NewTaskInput from './components/NewTaskInput'

const App = () => {
  const [tasks, setTasks] = useState([]);

  function addNewTask(task) {
    const itensCopy = Array.from(tasks);
    itensCopy.push({id: tasks.length, value: task});
    setTasks(itensCopy);
  }

  function updateTask({target}, index) {
    const itensCopy = Array.from(tasks);
    itensCopy.splice(index, 1, { id: index, value: target.value });
    setTasks(itensCopy);
  }

  function deleteTask(index) {
    const itensCopy = Array.from(tasks);
    itensCopy.splice(index, 1);
    setTasks(itensCopy);
  }

  return (
    <div className="App">
      <div className="App-header">
        <NewTaskInput onSubmit={addNewTask} />
        {tasks.map(({id, value}, index) => (
          <ListItem
            key={id}
            value={value}
            onChange={(event) => updateTask(event, index)}
            onDelete={() => deleteTask(index)}
          />
        ))}
      </div>
      <div className="Array-preview">
        <pre>
          {JSON.stringify(tasks, null, 4)}
        </pre>
      </div>
    </div>
  )
}

export default App;

Como havia dito este componente mantém um estado interno que é o Array contendo as nossas tarefas.

Existem também três funções: addNewTask, deleteTask e updateTask:

Em todas as funções eu não vou editar o Array do estado diretamente, pois estaria inflingindo uma regra importante do React: não mutar o estado diretamente. Sendo assim vou sempre criar uma cópia do Array, usando Array.from.

O método Array.from() cria uma nova instância de um Array quando for passado um array-like ou um iterable object como argumento. https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/from

Lógica para adicionar, atualizar e excluir tarefas.

addNewTask Essa é a função mais simples responsável apenas por adicionar novas tarefas, nela eu recebo o paramêtro task do evento onSubmit do nosso component NewTaskInput, crio a cópia do Array de tarefas atual, insiro minha nova tarefa com o método push, usando como id o length do array e como value o paramêtro task, por fim atualizo meu estado com a cópia do Array.

updateTask Para atualizar uma tarefa também é bem simples, eu recebo o paramêtro index para indicar qual elemento quero atualizar após isso vou utilizar o método splice,

O método splice altera o conteúdo de um Array, adicionando novos elementos enquanto remove elementos antigos, ou somente removendo elementos. https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

deleteTask Para excluir uma tarefa é basicamente a mesma coisa, utilizo o mesmo método splice porem sem o último argumento, já que neste caso não estou substituindo apenas excluindo.

E este é o resultado final: https:::i2.wp.com:media.giphy.com:media:kca4cHkPiQTNNNafYD:giphy

Este é o link do projeto no github caso queira modificar a partir dele: https://github.com/digital-heroes/dynamic-list-itens

É isso galera! foi um prazer enorme tomar um pouco do seu tempo. Espero que o post tenha ajudado bastante.

Obrigado pela leitura e até o próximo post!