React Hooks — useState e useEffect
No artigo de hoje vamos falar um pouco sobre as hooks, para que elas servem e o que podemos fazer com elas. As hooks foram introduzidas na versão 16.8 do ReactJS e mudou as formas de como são desenvolvidos os componentes React.
O que são hooks?
O termo hooking não surgiu especialmente para o framework React, ele já é usado em diversos ramos da programação de computadores e geralmente essa técnica se refere para quando ocorre alguma alteração ou melhoria em um ambiente computacional.
No entanto, o que queremos saber é o que são as hooks para o React, correto?
Antes de existirem as hooks, a forma de criar componentes era por meio de classes, porém depois do surgimento das hooks, todos e quaisquer componentes podem ser convertidos para componentes de função, isto significa que não precisamos mais escrever classes em projetos React! As principais motivações para existirem as hooks é a legibilidade e a menor complexidade para desenvolvermos componentes.
Ok, mas nesse caso, como que ficam os estados, as renderizações e o ciclo de vida de um componente se eu não tenho mais classes?
Para isso, os pessoal que desenvolve o framework criou hooks que são pré-definidas e que fazem todo esse trabalho. As mais famosas são o useState e o useEffect, além de existirem diversas outras, claro. Várias delas serão mostradas abaixo por meio de exemplos :)
Para caso você for seguir o artigo completo
Vamos modelar uma mini-aplicação que englobe o uso das hooks como um todo, cada hook que será apresentado abaixo será seguido do exemplo do tópico anterior, ou seja, será uma mini história sequencial, em linha reta.
useState
A função do useState, como o próprio nome dá a entender, serve para armazenar o estado do seu componente. Quando o estado é alterado, o componente é re-renderizado, ou seja, o componente reage a alterações de suas propriedades, daí vem o nome React.
Tá bom, entendi, o funcionamento é igual para o componente de classe, mas como usamos o useState?
Início da nossa mini história:
Vamos imaginar uma flor, a dormideira (em alguns locais ela é conhecida como sensitiva). A dormideira possui um comportamento um pouco diferente das flores comuns, pois a flor da dormideira se abre durante o dia e se fecha durante a noite. Como o nosso exemplo é apenas um exemplo, vamos supor que a nossa dormideira irá se fechar quando tocarmos nela, se tocarmos de volta ela irá se abrir.
Supondo que o nosso exemplo seguirá a regra citada acima, então devemos ter um estado para o nosso componente Flower. Para declarar um estado usando o useState fazemos da seguinte forma:
Para a figura acima, criamos uma função (arrow function) chamada Flower, essa função é chamada de componente funcional pois ela retorna um JSX, isto é, um componente React. Esse JSX está super simples, retornando apenas uma div com um texto “flor”. Além do retorno da função, ela também armazena um estado, o estado está sendo armazenado pelo useState.
Estrutura do useState:
Para o useState, é necessário conhecer três pontos principais, sendo eles:
- O primeiro argumento do array que é retornado pelo useState é o estado que será utilizado no componente, você pode dar qualquer nome a ele, no nosso exemplo o nome dado é open, pois iremos o utilizar para validar se a flor está aberta ou fechada.
- O segundo argumento do array que é retornado pelo useState é o setter do estado que será utilizado no componente. Sempre que for necessário atualizar este estado do componente você deve utilizá-lo. Qualquer nome pode ser atribuído a ele, porém uma boa prática é apenas colocar um prefixo “set”, sempre respeitando a prática de camelCase. No nosso exemplo, o nomeamos de setOpen.
- O terceiro item é o estado inicial que o estado irá receber, para isso basta passar o estado inicial como argumento do useState. No nosso exemplo, como o estado será um booleano, ele irá iniciar como false. O estado inicial não é obrigatório, caso você opte por não passar argumento, o estado inicial será undefined.
Componentes Funcionais podem ter quantos estados forem necessário, e cada estado pode receber qualquer tipo, desde numbers à objetos complexos. Porém, conforme o componente for crescendo e ficando cada vez mais complexo, surgem opções melhores para o gerenciamento de estados, por exemplo, o useReducer, uma outra hook da própria api do React.
O exemplo acima é um exemplo simples da estrutura do useState. como estamos construindo um exemplo completo, então nada melhor do que vermos na prática tudo isso:
Não se importe caso não entender o código completo, pois estamos usando uma lib de interface gráfica: Material-UI. Vamos focar apenas no uso do useState.
- Observe a declaração na linha 20, ali temos o estado, igual citado lá no início.
- Observe que temos um botão na linha 33, ele é emite um evento quando o botão é clicado, disparando a função handleClick.
- Por sua vez, na linha 22, o evento que foi disparado faz com que o estado seja atualizado. Para isso utilizamos o setOpen para atualizar o estado da nossa flor. Simples assim.
- Utilizamos o estado open na linha 37, queremos mostrar a imagem da flor aberta caso o estado open for verdadeiro, e a imagem da flor fechada caso contrário.
Eis o resultado até agora:
O exemplo completo (incluindo tudo que vier depois) está disponível neste repositório: https://github.com/thiagoissao/hooks-article.
useEffect
Estamos construindo uma flor que reage a eventos do nosso cotidiano (dia e noite), uma flor que abre durante o dia e fecha durante a noite. Então neste tópico irei apresentar uma forma de implementação para fazer esta simulação.
O useEffect é uma hook disponibilizada pela api do React que reage a eventos que dependem de determinados estados de um componente. Com o useEffect é possível implementar todo o ciclo de vida de um componente React, para saber mais sobre os ciclos de vida de um componente React abra este link: https://pt-br.reactjs.org/docs/state-and-lifecycle.html
Vamos fazer uma lógica para tratar a regra dessa flor utilizando as duas hooks vistas até agora, abaixo segue o código implementado
A primeira linha da imagem acima representa o estado que será controlado para definir se o momento atual está dia ou noite.
Na terceira linha temos o uso do useEffect, para utilizar esta hook é necessário passar dois argumentos:
- O primeiro argumento é uma função de callback onde ficará todas as suas operações para aquele useEffect, geralmente é aqui onde ficarão as chamadas de api e alterações de estados para alguns casos específicos. No nosso exemplo, criamos uma variável
interval
que será executado a cada 5 segundos, e toda vez que ela for executada, irá inverter o estadoisNight
; - O segundo argumento é um vetor de dependências. Um vetor vazio significa que o useEffect será executado apenas uma vez, isto faz com que ele tenha o mesmo comportamento do método componentDidMount para componentes de classe. Este vetor pode receber quantos itens forem necessários, quando um item desse vetor for alterado, o useEffect é executado. Por exemplo, caso fosse passado neste vetor o estado
open
, toda vez que o estado open fosse alterado o useEffect seria executado.
Perceba que na função de callback (o primeiro paramêtro) do useEffect existe um return () => clearInterval(interval)
, este return faz com que o useEffect tenha o mesmo comportamento do método componentWillUnmount para componentes de classe, isto significa que ele será executado momento antes do componente ser desconstruído.
Por fim, devemos alterar o estado da flor para todo momento que o estado isNight
for alterado, para isso vamos criar um novo useEffect para tratar este caso. Abaixo segue o código implementado:
Sem muitos segredos, apenas utilizando o que já foi revisado acima. O useEffect será executado sempre que isNight
for alterado, a função que ela executará será setFlowerRules
. Nesta função temos a lógica para validar se está dia ou noite, e com isso, conseguimos alterar o estado da flor.
Em projetos de larga escala, alguns componentes crescem em complexidade e com isso problemas de concorrência podem acabar gerando bugs imprevistos, o que não deve acontecer em componentes bem estruturados. Destaco esse ponto pois os casos mais comuns para bugs de concorrência geralmente são causados por uso excessivo dessas funções que podem causar efeitos colaterais em diversos estados da aplicação. Portanto, o useEffect pode e deve ser sempre utilizado, porém sempre com muito cuidado aos detalhes e aos possíveis impactos que ele pode causar.
Abaixo está o código completo e com um efeito visual para entendermos o que está acontecendo:
Este é o código completo do nosso exemplo, atente-se mais aos detalhes do uso da hook do que com o JSX e as estilizações. Analisando o código vemos que agora a nossa dormideira reage a dois eventos: Clicando sobre ela e por meio do tempo. O resultado final está logo abaixo:
Infelizmente a gravação da tela não ficou na qualidade que eu gostaria, mas aposto que ao vivo fica bem mais legal ver tudo funcionando.
Este exemplo foi feito para tentar explicar de forma simples o conceito dessas duas principais hooks. A ideia da dormideira eu tirei enquanto estava lendo um livro sobre a importância do sono para o ser humano (O sono regular é muito importante para nossa saúde, inclusive pensando a longo prazo), logo eu pensei, porque não escrever o conceito de hooks e atrelar isso a essa planta?
Estes conceitos você não irá usar apenas em dormideiras, e sim, em toda a sua jornada React, assim como eu estou utilizando.
Existem muitas outras hooks que ajudam na hora de desenvolver componentes, mas isso podemos deixar para outro artigo :)
Espero ter ajudado e até mais!
Link do Repositório com os exemplos: https://github.com/thiagoissao/hooks-article
My Social Networks: