A versão 16.8.0, é o primeiro release que traz suporte estável aos Hooks. Com isso, simplificando a vida de programadores e curiosos. Permitindo o uso de estado e outros recursos da biblioteca sem escrever uma classe.
Regras dos Hooks
- Apenas chame os Hooks no nível mais alto. Não chame Hooks dentro de loops, condicionais ou funções aninhadas. O React identifica os hooks de um componente pela ordem em que eles foram chamados.
- Apenas chame os Hooks em componentes funcionais. Não chame Hooks em funções JavaScript comuns. (Há apenas um outro lugar válido para se chamar Hooks — dentro dos seus próprios Hooks customizados.)
Confira o link para o plugin do eslint, para que as regras sejam revisadas automaticamente.
Tipos de Hooks
- Hook de estados - useState - permite ler e armazenas as informações de maneira mais fácil e prática no estado, eliminando alguns componentes de classes e substituindo por componentes funcionais.
- Hook de efeitos - useEffect - utilizado para executar funções que necessitam ou realizam algum efeito no componente. Ex: mutations, subscriptions, timers e logging. Tem o mesmo efeito que os componentDidMount e componentDidUpdate tem nas classes.
- Hook customizado - Crie seus próprios hooks e extraia a lógica de um componente em funções reutilizáveis.
- Outros Hooks - Hooks nativos com funções específicas.
Os Hooks existentes podem ser classificados como básicos e adicionais. Veja a lista abaixo:
Hooks básicos:
Hooks adicionais:
Hook de estados
Vamos olhar o hook de estado. Abaixo veremos um exemplo:
1 | import React, { useState } from 'react' |
O hook nesse caso é o useState. Ele está recebendo um estado inicial e retorna um array com dois valores. Sendo o primeiro valor o estado atual e o segundo uma função para atualizar esse estado. O useState não tem a funcionalidade idêntica ao setState que é utilizado em classes. Quando se é passado um objeto para o setState, o mesmo combina o valor que estamos passando com o antigo. Já no useState, todo o estado do hook será alterado, mas temos o mesmo efeito usando o operador de spread. Ex: useState({ …oldState, …newState }); .
Exemplo de um objeto no estado inicial:
1 | function Counter() { |
Também, podemos chamar mais de uma vez o nosso hook useState no nosso componente.
1 | function Counter() { |
Hook de efeitos
Agora vamos falar do hook useEffect. O mesmo permite que seu componente em forma de função tenha acesso aos métodos de ciclo de vida sem precisar refatorar seu componente para uma classe. Abaixo, um exemplo:
1 | import React, { useState, useEffect } from 'react' |
O título será alterado de acordo com a atualização do estado do componente. O useEffect nesse contexto, seria o mesmo que o ComponentDidMount e também o ComponentDidUpdate. Será chamada a função passada tanto quando o componente é montado quando é atualizado.
O useEffect te ajuda ao desmontar os recursos, exatamente como faria com ComponentWillUnmount.
1 | function Example() { |
Acima temos o evento de mousemove configurado para alterar o estado do componente de acordo com o movimento do mouse e quando o componente for desmontado será rodado o removeEventListener. Também será chamada quando for detectado que o useEffect precisa rodar novamente, ou seja em cada render. A cada alteração no estado do componente nosso evento está sendo removido e adicionado novamente. Agora não queremos isso e precisamos que o evento seja adicionado na montagem e na desmontagem.
Vamos utilizar o segundo argumento que o useEffect recebe, que é uma lista dos valores que devem mudar para que ele rode novamente. Passando uma lista vazia, ele irá rodar apenas quando é montado e a função de limpeza apenas quando é desmontado.
1 | function Example() { |
Os Event listeners serão chamados apenas quando precisamos. O segundo parâmetro pode ser utilizado para dizer quando nosso efeito vai rodar. Abaixo, um exemplo:
1 | function Status(props) { |
Quando friend.id for alterado, iremos chamar o unsubscribeFromUserStatus com id anterior e depois chamar o subscribeToUserStatus com id atual, assim temos consistência na limpeza dos recursos de forma simples.
Hook customizado
Os Hooks são totalmente desacoplados de componentes, o que nos permite combiná-los para criar novos hooks mais específicos e compartilhar lógica entre nossos componentes.
Começaremos com o exemplo abaixo:
1 | import React, { useState, useEffect } from 'react'; |
Também vamos precisar de uma lista de contatos e exibir seus respectivos status.
1 | import React, { useState, useEffect } from 'react'; |
Com isso, temos uma repetição de código. Resolveremos isso, ao extrair a lógica repetida em um hook customizado.
1 | import React, { useState, useEffect } from 'react'; |
Agora a lógica que tínhamos em nossos componentes, está em uma função separada (um padrão: que os hooks tenham o prefixo use). Abaixo, exemplo da utilização:
1 | function UserStatus(props) { |
1 | function UserListItem(props) { |
Agora temos uma lógica simplificada. Também é possível criar hooks para lidar com bibliotecas externas:
1 | import React, { useState, useEffect } from 'react'; |
Acima, a cada novo evento no stream do observable temos uma atualização no estado. Abaixo, um exemplo usando a bilbioteca RxJS.
1 | import React from 'react'; |
Considerações finais
Não foi falado muito sobre os Outros Hooks, mas podemos ver a listagem no ínício deste artigo. Mais sobre os Hooks, podem ser vistos na documentação oficial e em próximos artigos.