Um guia simples e prático sobre o useEffect do React

O useEffect é um hook do React que permite executar efeitos colaterais em componentes funcionais. Ele é uma maneira poderosa de interagir com o ciclo de vida do componente e executar ações que não estão diretamente relacionadas à renderização do componente, como lidar com requisições assíncronas, adicionar e remover event listeners e atualizar o estado de um componente. O useEffect é um dos hooks mais utilizados no React, e sua flexibilidade o torna uma ferramenta essencial para desenvolvedores de React que buscam criar componentes funcionais mais robustos e eficientes.

Ao usar o useEffect, você pode executar tarefas assíncronas, manipular o DOM e atualizar o estado do componente, entre outras coisas. Ele é uma maneira de trabalhar com efeitos colaterais, sem precisar lidar com o ciclo de vida do componente diretamente. Além disso, o useEffect oferece um controle mais granular sobre quando uma ação deve ser executada, graças ao seu dependency array. Isso permite que você controle exatamente quando o useEffect é executado e evite efeitos colaterais desnecessários. 

Como usar

Para usar o useEffect, você precisa importá-lo do React. A sintaxe básica do useEffect é a seguinte:

Imagem mostrando um componente react com useEffect

O useEffect recebe uma função como parâmetro, que será executada após a renderização do componente. O que essa função faz é chamado de efeito colateral.

Além disso, o useEffect pode receber um segundo parâmetro opcional, que é um array de dependências. Em outros hooks do React como o useMemo e o useCallback esse array é obrigatório. Esse array é uma lista de variáveis que o useEffect observará para saber quando executar a função novamente. Se uma variável listada no array de dependências mudar de valor, a função será executada novamente. Caso contrário, a função será executada apenas na primeira renderização do componente.

Nesse exemplo, o useEffect será executado sempre que o valor de count for alterado. Ao usar o array de dependências, você pode controlar exatamente quando a função é executada e evitar efeitos colaterais desnecessários. ATENÇÂO, pois se o array de dependências for omitido, a função será executada em todas as renderizações do componente.

Ciclo de Vida do Componente

O useEffect é uma ferramenta poderosa para lidar com o ciclo de vida do componente e executar ações que não estão diretamente relacionadas à renderização do componente.

Existem três métodos do ciclo de vida do componente em componentes de classe que correspondem ao useEffect: componentDidMount, componentDidUpdate e componentWillUnmount.

O componentDidMount é chamado depois que o componente é montado no DOM. Você pode usar o useEffect com um array de dependências vazio para executar ações semelhantes ao componentDidMount.

O componentDidUpdate é chamado sempre que o componente é atualizado no DOM. Você pode usar o useEffect com um array de dependências para executar ações semelhantes ao componentDidUpdate.

O componentWillUnmount é chamado antes de o componente ser removido do DOM. Você pode usar o useEffect com uma função de limpeza para executar ações semelhantes ao componentWillUnmount.

Usando o useEffect, você pode ter mais controle sobre quando esses métodos do ciclo de vida são executados e também pode combinar vários efeitos colaterais em um único useEffect. Isso torna o código mais organizado e fácil de manter.

Atualizações de Estado

Quando uma atualização de estado é feita em um componente, o React renderiza o componente novamente e executa o useEffect novamente.

Isso significa que, se você tiver um useEffect que depende do valor de uma variável de estado, ele será executado novamente sempre que essa variável mudar. Isso é muito útil para garantir que seu código esteja sempre atualizado e reativo às mudanças no estado do componente. Além disso, o array de dependências do useEffect permite que você controle exatamente quando a função é executada em resposta às mudanças de estado.

Quando o array de dependências está vazio, o useEffect é executado apenas uma vez, quando o componente é montado no DOM. No entanto, se você incluir uma variável de estado ou propriedade no array de dependências, o useEffect será executado sempre que essa variável ou propriedade mudar. Isso pode causar um loop infinito de atualizações, o que é muito ruim para o desempenho do aplicativo.

Para evitar atualizações infinitas, você pode usar o array de dependências para especificar exatamente quais variáveis ou propriedades o useEffect deve observar. Isso garante que a função seja executada apenas quando necessário e não em cada atualização do componente.

No entanto, é importante lembrar que o array de dependências deve ser cuidadosamente escolhido para evitar a execução desnecessária ou insuficiente da função do useEffect. Se você incluir muitas variáveis no array, o useEffect será executado com muita frequência, o que pode causar problemas de desempenho. Por outro lado, se você não incluir variáveis suficientes, o useEffect pode não ser executado quando necessário, o que pode levar a erros no aplicativo.

Requisições

Podemos usar o useEffect para disparar a requisição assim que o componente for montado, e atualizar o estado do componente com os dados recebidos


Neste exemplo, criamos um estado data que inicialmente é null, e disparamos a requisição usando o axios dentro do useEffect. Como a função get do axios retorna uma Promise, usamos o .then e o .catch para processar o resultado da requisição em caso de sucesso ou de erro. Quando os dados são recebidos, atualizamos o estado do componente com a função setData ou setError em caso de erro. Por fim, renderizamos os dados na tela com um operador ternário para lidar com o caso em que os dados ainda não foram carregados. Temos o condicionar com o error que serve para mostrar uma mensagem na tela para o caso de erro.

É importante notar que passamos um array vazio [] como segundo argumento para o useEffect. Isso garante que o useEffect só será executado uma vez, quando o componente for montado. Se não passássemos esse segundo argumento, o useEffect seria executado a cada atualização do componente, causando um loop infinito de requisições.

Veja outro exemplo utilizando paginação:


O exemplo mostra como fazer uma requisição assíncrona utilizando a biblioteca axios. O objetivo é fazer uma paginação de posts retornados de uma API, onde cada página possui no máximo 10 posts.

No estado do componente, são armazenadas as informações da página atual, do número total de páginas, dos dados retornados pela API e de um possível erro. No useEffect, a URL da requisição é construída com base no valor de currentPage, que é atualizado sempre que o usuário clica em um botão de páginação.

Ao fazer a requisição, o then trata a resposta da API, atualizando o estado com os dados retornados e calculando o número total de páginas a partir do cabeçalho da resposta. Em caso de erro, o catch trata a exceção, atualizando o estado com uma mensagem de erro.

Por fim, o conteúdo a ser renderizado é colocado no retorno do componente, indicado por um comentário. No exemplo, isso seria uma lista de posts com um sistema de paginação que permite ao usuário navegar entre as diferentes páginas de posts.

Event Listeners

O useEffect também pode ser utilizado para adicionar e remover event listeners. Isso é útil quando queremos manipular eventos do DOM em componentes React. Vamos supor que queremos adicionar um event listener para quando o usuário move o mouse para fora da tela. Podemos fazer isso usando o useEffect e o objeto window da seguinte maneira:


Nesse exemplo, estamos criando uma função handleMouseLeave que será chamada quando o mouse sair da tela. Em seguida, estamos adicionando um listener de mouseout no objeto window com a função addEventListener. Novamente, passamos um array vazio como segundo argumento para o useEffect, indicando que queremos que o efeito seja executado somente uma vez, quando o componente é montado.

Por fim, estamos retornando uma função que remove o listener criado, usando o removeEventListener. Essa função será executada quando o componente for desmontado, evitando possíveis memory leaks.

Dessa forma, podemos adicionar e remover event listeners de forma segura em qualquer objeto, como o window, usando o useEffect.

Melhores práticas

Existem algumas melhores práticas para usar o useEffect de forma eficaz. A primeira delas é usar o useEffect para lidar com efeitos colaterais, como chamadas a APIs externas, atualizações de estado ou adição de event listeners. O useEffect é uma forma de centralizar a lógica de efeitos colaterais em um único local, o que ajuda a evitar erros e torna o código mais fácil de manter.

Outra prática importante é cuidar do array de dependências passado como segundo argumento para o useEffect. Este array determina quando o efeito deve ser executado novamente. Se o array estiver vazio, o efeito só será executado uma vez. Se houver valores no array, o efeito será executado sempre que um desses valores mudar. É importante tomar cuidado com o uso do array de dependências, já que o useEffect pode entrar em um loop infinito se as dependências não forem corretamente configuradas.

Quando evitar o uso

Embora o useEffect seja uma ferramenta poderosa para lidar com efeitos colaterais em componentes React, há momentos em que pode ser melhor evitá-lo. Um exemplo seria quando o componente é simples o suficiente para não ter efeitos colaterais que precisem ser tratados. Em componentes pequenos e estáticos, o uso do useEffect pode adicionar complexidade desnecessária e tornar o código mais difícil de entender e manter.

Outra situação em que pode ser melhor evitar o useEffect é quando os efeitos colaterais precisam ser tratados em vários componentes em diferentes níveis da árvore de componentes. Nesse caso, pode ser mais eficiente criar um componente especializado para lidar com esses efeitos colaterais, em vez de adicionar o useEffect a cada componente que precisa desses efeitos. Isso ajuda a evitar a duplicação de código e torna o código mais fácil de manter.

Veja mais nesse vídeo








Comentários