useEffect do React js


 

Como funciona o useEffect no React? Guia completo com exemplos

React Hooks JavaScript Iniciantes

Você já precisou executar uma ação quando um componente aparece na tela, atualizar alguma informação quando um valor muda ou iniciar um temporizador no React? É exatamente nesse tipo de situação que o useEffect pode ajudar.

Neste guia, você vai aprender o que é o useEffect, para que ele serve, como funciona por trás dos panos, como utilizar suas dependências e como evitar os erros mais comuns. Tudo isso com exemplos práticos e explicações passo a passo.

1. O que é o useEffect no React?

O useEffect é um Hook do React que permite executar uma tarefa depois que o React atualiza a tela, quando essa tarefa precisa sincronizar o componente com algo externo a ele.

Mas o que significa Hook? Um Hook é uma função especial do React que permite utilizar recursos do React dentro de componentes funcionais. O useEffect é um desses recursos.

E o que seria algo externo? Pode ser um temporizador, uma conexão com um servidor, um evento do navegador ou uma biblioteca que não é controlada diretamente pelo React.

Imagine uma tarefa automática.

Você entra em um quarto e acende a luz. Depois, quando a temperatura muda, um aparelho ajusta o ar-condicionado. O useEffect é parecido: ele permite configurar uma ação para acompanhar determinadas mudanças e manter algo sincronizado.

A forma básica do useEffect é esta:

Estrutura básica do useEffect
import { useEffect } from 'react';

useEffect(() => {
  // Tarefa que precisa ser executada.
}, []);

Esse código apresenta a estrutura do Hook. O comentário representa a tarefa que você deseja executar. O array vazio, chamado de lista de dependências, informa que o efeito não depende de nenhum valor reativo específico. Vamos entender exatamente o que isso significa nas próximas seções.

Atenção: não use useEffect para qualquer tarefa. Se você só precisa calcular um valor a partir de outros valores, geralmente pode fazer isso diretamente durante a renderização. O useEffect é mais indicado para sincronização com sistemas externos.

2. Para que serve o useEffect?

O useEffect é útil quando o componente precisa manter uma relação com algo que funciona fora do fluxo normal de renderização do React.

  • Temporizadores: iniciar um contador e limpá-lo quando necessário.
  • Eventos do navegador: observar mudanças no tamanho da janela.
  • Conexões: conectar e desconectar um serviço externo.
  • Bibliotecas externas: sincronizar um componente com uma ferramenta de terceiros.
  • Armazenamento do navegador: sincronizar preferências com o localStorage, quando isso for necessário.

Uma observação importante: nem toda chamada a uma API precisa obrigatoriamente de useEffect. Se a busca acontece porque o usuário clicou em um botão, por exemplo, ela pode ficar diretamente na função que trata o clique. Se a busca precisa acompanhar a exibição de um componente ou uma mudança de filtros, o useEffect pode ser apropriado.

3. Como o useEffect funciona por trás dos panos?

Para entender o useEffect, primeiro precisamos conhecer a renderização.

O que é renderização?

Renderização é o processo pelo qual o React executa seu componente para descobrir qual interface deve aparecer na tela.

Quando um estado muda, o React normalmente executa o componente novamente e atualiza a interface conforme necessário.

O useEffect participa desse processo em uma etapa posterior à atualização da tela, conforme as dependências e as regras do React.

O caminho mais fácil de lembrar:

  1. O React executa o componente.
  2. O React calcula a interface que deve aparecer.
  3. O React atualiza a tela, quando necessário.
  4. O efeito é executado quando suas regras de dependência indicam que ele deve ser executado.

Essa é uma explicação simplificada. O momento exato em que um efeito é executado pode variar conforme o tipo de renderização e a interação com o navegador.

O que acontece quando um valor muda?

Imagine que você tenha um componente com uma variável de estado chamada contador. Quando o contador muda, o React renderiza novamente o componente. Se o efeito depende desse contador, o React compara o valor anterior com o atual e decide se precisa executar o efeito novamente.

Se o efeito já tiver sido executado e precisar ser refeito, a função de limpeza da execução anterior será chamada antes da nova execução. Ao desmontar o componente, o React também executa a limpeza do efeito, quando ela existe.

4. Entendendo as três partes do useEffect

A chamada do useEffect possui três partes que você precisa conhecer:

As três partes
useEffect(
  () => {
    // 1. Função do efeito
  },
  [valor] // 2. Lista de dependências
);

Parte 1 — A função do efeito

É a função que contém a tarefa que você deseja executar. Ela pode configurar uma conexão, iniciar um temporizador ou registrar um evento.

Parte 2 — A lista de dependências

É o array que informa quais valores reativos são utilizados pelo efeito e devem ser observados. Um array é uma lista de valores escrita entre colchetes.

Parte 3 — A função de limpeza

A função de limpeza é opcional. Ela serve para desfazer aquilo que o efeito configurou, como cancelar um temporizador ou remover um evento.

Para retornar uma função de limpeza, escrevemos uma função dentro da função do efeito:

Exemplo de limpeza
useEffect(() => {
  // Configura alguma coisa.

  return () => {
    // Desfaz a configuração.
  };
}, []);

Não é obrigatório retornar uma função de limpeza em todos os efeitos. Ela é necessária quando existe algo que precisa ser desfeito ou encerrado.

5. O array de dependências: o segredo do useEffect

As dependências são os valores que determinam quando o efeito precisa ser executado novamente. Existem três formas comuns de escrever o useEffect.

Forma Comportamento
useEffect(fn) Executa após cada renderização concluída do componente.
useEffect(fn, []) Executa na montagem inicial, sem depender de valores reativos específicos. Pode executar novamente em verificações de desenvolvimento do Strict Mode.
useEffect(fn, [valor]) Executa na montagem inicial e novamente quando o valor da dependência muda.

Forma 1 — Sem array de dependências

Quando você não fornece o segundo argumento, o efeito é executado após cada renderização concluída. Isso pode ser útil em situações específicas, mas exige cuidado para evitar trabalho desnecessário ou ciclos de renderização.

Forma 2 — Com array vazio

Quando você escreve [], o efeito não depende de valores reativos específicos. Em condições normais de produção, ele é executado na montagem inicial do componente e limpo quando necessário.

No ambiente de desenvolvimento, o Strict Mode pode executar um ciclo adicional de configuração e limpeza para ajudar a encontrar efeitos mal implementados. Por isso, não é correto garantir que o efeito será chamado exatamente uma vez em todos os ambientes.

Forma 3 — Com dependências

Quando você fornece valores no array, o React compara cada dependência com seu valor anterior. Se alguma dependência mudou, o efeito é executado novamente.

Regra prática: inclua as dependências reativas utilizadas pelo efeito. Não retire valores do array apenas para tentar fazer o efeito executar menos vezes. Se isso causar um comportamento inesperado, reorganize o código para que o efeito tenha as dependências corretas.

6. Exemplo prático 1: observar um contador

Vamos criar um contador que aumenta quando o usuário clica em um botão. O useEffect vai observar o contador e mostrar uma mensagem no console sempre que o valor mudar.

O console é uma área do navegador usada por desenvolvedores para visualizar mensagens de diagnóstico. Ele pode ser aberto nas ferramentas de desenvolvedor do navegador.

Contador.jsx
import { useEffect, useState } from 'react';

function Contador() {
  const [contador, setContador] = useState(0);

  useEffect(() => {
    console.log('Contador:', contador);
  }, [contador]);

  return (
    <div>
      <p>Valor: {contador}</p>

      <button
        onClick={() =>
          setContador(contador + 1)
        }
      >
        Aumentar
      </button>
    </div>
  );
}

export default Contador;

Entendendo o código passo a passo

1

Importamos os Hooks.

useState guarda o contador. useEffect permite executar a tarefa que observa o contador.

2

Criamos o estado.

useState(0) inicia o contador em zero. A variável contador contém o valor atual, e setContador é a função utilizada para pedir a atualização desse valor.

3

Observamos a mudança.

O useEffect utiliza [contador] como lista de dependências. Quando o contador muda, o efeito pode ser executado novamente.

4

Atualizamos o contador.

Quando o usuário clica no botão, setContador solicita que o React atualize o estado. O React renderiza novamente o componente e, após a atualização, o efeito observa o novo valor.

Resultado esperado

Valor: 0 → Valor: 1 → Valor: 2 → Valor: 3

No console, você verá mensagens como Contador: 0, Contador: 1 e Contador: 2 conforme o contador muda. Em desenvolvimento, o Strict Mode pode produzir mensagens adicionais na montagem inicial.

Por que funciona? Porque o React compara a dependência contador com o valor anterior. Quando ele muda, o efeito é executado novamente.

7. Exemplo prático 2: iniciar e limpar um temporizador

Agora vamos criar um relógio simples que atualiza a cada segundo. Esse exemplo mostra uma situação em que a função de limpeza é muito importante.

Um temporizador continua funcionando até ser cancelado. Se o componente deixar de ser exibido, não queremos manter um temporizador desnecessário funcionando.

Relogio.jsx
import { useEffect, useState } from 'react';

function Relogio() {
  const [segundos, setSegundos] = useState(0);

  useEffect(() => {
    const intervalo = setInterval(() => {
      setSegundos((anterior) => anterior + 1);
    }, 1000);

    return () => {
      clearInterval(intervalo);
    };
  }, []);

  return (
    <p>
      Segundos: {segundos}
    </p>
  );
}

export default Relogio;

Entendendo cada parte

1. O estado começa em zero. O valor de segundos é mostrado na tela e atualizado pela função setSegundos.

2. O setInterval inicia o temporizador. Essa função do JavaScript executa uma tarefa repetidamente, usando o intervalo de tempo informado. O valor 1000 representa mil milissegundos, ou seja, um segundo.

3. A função atualiza o estado. A expressão setSegundos(anterior => anterior + 1) recebe o estado anterior e solicita que o próximo valor seja um segundo maior. Essa forma é útil quando o novo estado depende do anterior.

4. O efeito retorna uma função de limpeza. A função clearInterval(intervalo) cancela o temporizador criado anteriormente.

5. O array está vazio. O temporizador não precisa ser recriado a cada atualização dos segundos. O React configura o efeito na montagem inicial e executa a limpeza quando necessário.

Resultado esperado

Segundos: 0 → Segundos: 1 → Segundos: 2 → Segundos: 3...

Por que funciona? O temporizador atualiza o estado a cada segundo. A atualização provoca uma nova renderização, e o React mostra o novo número. A função de limpeza impede que o temporizador continue ativo depois que o componente for desmontado.

Importante: o contador deste exemplo mede o tempo decorrido de forma aproximada. O navegador pode atrasar temporizadores, por isso ele não é adequado para medir tempo com precisão.

8. Comparando o useEffect com situações do cotidiano

Vamos usar duas comparações simples para fixar o que aprendemos.

Exemplo 1 — O alarme do relógio

Imagine que você configure um alarme para tocar quando chegar determinado horário. Você não precisa configurar o alarme novamente a cada segundo. Ele fica configurado enquanto for necessário e deve ser cancelado quando você não quiser mais utilizá-lo.

Isso se parece com um efeito que configura um temporizador e o limpa depois.

Exemplo 2 — Uma lâmpada automática

Imagine uma lâmpada que acende quando um sensor detecta movimento. O sensor observa uma condição e reage quando ela muda.

Isso se parece com um efeito que acompanha um valor e executa uma ação quando esse valor muda. A comparação ajuda a entender a ideia, embora o useEffect não seja um sensor automático: você precisa informar corretamente suas dependências.

9. Erros comuns ao utilizar useEffect

Erro 1 — Esquecer uma dependência

Quando um efeito utiliza um valor reativo e esse valor não está na lista de dependências, o efeito pode continuar usando uma versão antiga desse valor. Esse problema é conhecido como fechamento desatualizado, ou stale closure.

Exemplo problemático
useEffect(() => {
  console.log(contador);
}, []);

Se contador é um valor de estado, o efeito acima não acompanhará suas mudanças. Ele utiliza o valor capturado na renderização em que o efeito foi configurado.

Como resolver: se a intenção é observar o contador, inclua-o nas dependências.

Forma corrigida
useEffect(() => {
  console.log(contador);
}, [contador]);

Erro 2 — Criar um ciclo infinito de renderizações

Uma renderização acontece quando o React executa o componente para calcular a interface. Se o efeito atualiza um estado e, por causa disso, é executado novamente sem uma condição adequada, você pode criar um ciclo repetitivo.

Exemplo problemático
useEffect(() => {
  setContador(contador + 1);
}, [contador]);

O efeito aumenta o contador. O contador muda, então o efeito executa novamente e aumenta o contador mais uma vez. O ciclo pode continuar indefinidamente.

Como resolver: não utilize um efeito para realizar uma atualização que pode acontecer diretamente em um evento, como um clique. Se você deseja incrementar um contador ao clicar, faça a atualização no manipulador do botão.

Erro 3 — Usar useEffect para calcular valores simples

Imagine que você tem um preço e uma quantidade e deseja descobrir o total. Se ambos já estão disponíveis no componente, você normalmente não precisa criar outro estado e usar um efeito para calcular o total.

Forma simples
const preco = 10;
const quantidade = 3;

const total = preco * quantidade;

O resultado será 30. O cálculo pode acontecer durante a renderização sem precisar de useEffect.

Erro 4 — Criar objetos ou funções que mudam de identidade

O React compara as dependências usando Object.is. Objetos e funções criados novamente a cada renderização geralmente têm uma identidade diferente, mesmo quando parecem iguais.

Isso pode fazer um efeito executar mais vezes do que você esperava.

Como resolver: quando possível, crie o objeto ou a função dentro do efeito, ou reorganize o código para depender de valores simples. Utilize useMemo ou useCallback apenas quando houver uma razão real para preservar uma identidade entre renderizações.

Erro 5 — Não limpar recursos externos

Um temporizador que continua ativo, um evento que permanece registrado ou uma conexão que não é encerrada pode causar trabalho desnecessário e comportamentos inesperados.

Como resolver: retorne uma função de limpeza quando o efeito configurar um recurso que precisa ser encerrado.

Erro 6 — Colocar useEffect dentro de uma condição

Os Hooks devem ser chamados no nível superior do componente ou de outro Hook personalizado. Não os coloque dentro de if, loops ou funções comuns que são chamadas de maneira condicional.

Forma correta: chame o useEffect no nível superior e coloque a condição dentro da função do efeito, quando necessário.

10. Boas práticas para usar useEffect

  • Use efeitos para sincronização externa: conexões, eventos, temporizadores e integrações.
  • Declare as dependências corretas: siga os avisos da regra exhaustive-deps do ESLint para React Hooks.
  • Limpe o que configurar: cancele temporizadores, remova eventos e encerre conexões quando necessário.
  • Evite estados desnecessários: valores que podem ser calculados diretamente não precisam necessariamente de um estado separado.
  • Prefira eventos para ações do usuário: enviar um formulário após um clique deve normalmente acontecer na função que trata esse evento.
  • Não tente controlar a execução com truques: o array de dependências deve refletir os valores reativos usados pelo efeito.
  • Teste com o Strict Mode: em desenvolvimento, o React pode fazer verificações extras. Seu efeito deve funcionar corretamente quando configurado, limpo e configurado novamente.

Uma regra para guardar: antes de criar um useEffect, pergunte: “Preciso sincronizar meu componente com alguma coisa externa?”. Se a resposta for não, talvez você não precise desse Hook.

11. Pequeno exercício para praticar

Agora é sua vez. Imagine que você tem um componente que mostra o nome de uma pessoa e deseja exibir uma mensagem no console sempre que esse nome mudar.

Desafio

  1. Crie um estado chamado nome, começando com a string 'Ana'.
  2. Crie um useEffect que mostre o nome no console.
  3. Coloque a variável nome no array de dependências.
  4. Adicione um botão que altere o nome para 'Pedro'.
  5. Clique no botão e observe o console.

Antes de olhar a resposta, tente montar o código por conta própria. O objetivo é entender a relação entre estado, renderização e dependências.

Ver resposta do exercício
Resposta — Nome.jsx
import { useEffect, useState } from 'react';

function Nome() {
  const [nome, setNome] = useState('Ana');

  useEffect(() => {
    console.log(nome);
  }, [nome]);

  return (
    <div>
      <p>Nome: {nome}</p>

      <button
        onClick={() => setNome('Pedro')}
      >
        Mudar nome
      </button>
    </div>
  );
}

export default Nome;

Quando o componente é montado, o efeito mostra Ana. Quando você clica no botão, o estado muda para Pedro, o React renderiza novamente o componente e o efeito mostra o novo nome.

12. Resumo: o que você precisa lembrar

  • O useEffect permite sincronizar componentes com sistemas externos.
  • A função do efeito contém a tarefa que será executada.
  • O array de dependências informa quais valores reativos devem ser observados.
  • Sem array, o efeito é executado após cada renderização concluída.
  • Com [], o efeito é configurado na montagem inicial, respeitando as verificações adicionais do ambiente de desenvolvimento.
  • Com dependências, o efeito é executado novamente quando alguma delas muda.
  • A função de limpeza desfaz a configuração anterior quando necessário.
  • O useEffect não deve ser usado para todo cálculo ou toda ação do usuário.
  • Os efeitos devem funcionar corretamente mesmo quando o React os configura e limpa mais de uma vez.

13. Conclusão

O useEffect é uma ferramenta importante do React, mas seu uso fica muito mais fácil quando você entende a finalidade dele: manter seu componente sincronizado com algo externo.

Comece com exemplos pequenos. Primeiro, observe um contador. Depois, experimente criar um temporizador com limpeza. Por fim, pratique acompanhar mudanças de valores e trabalhar com eventos do navegador.

Você não precisa decorar todas as regras de uma vez. Entenda o motivo de cada dependência e pergunte sempre se existe algo externo que realmente precisa ser sincronizado. Esse raciocínio ajudará você a escrever componentes mais simples e evitar muitos erros.

14. Continue aprendendo React


Comentários

Postagens mais visitadas deste blog

useMemo do React js

useState do React js