Como usar corretamente os hooks useEffect e useState do React

Última atualização: 28/01/2026
autor: Isaac
  • useState e useEffect concentram a maior parte do estado e dos efeitos colaterais dos componentes funcionais do React, substituindo muitos métodos clássicos do ciclo de vida.
  • Um efeito pode incluir lógica de limpeza que retorna uma função, permitindo gerenciar assinaturas, intervalos e outros recursos externos sem vazamentos de memória.
  • O array de dependências controla quando cada efeito é executado e deve conter todos os valores reativos usados ​​nele, equilibrando correção e desempenho.
  • Separar a lógica em vários pequenos useEffects por responsabilidade melhora a legibilidade, facilita a reutilização e reduz erros comuns, como renderizações infinitas ou dependências incorretas.

Hooks useState e useEffect do React

Se você trabalha com React diariamente, dominar useState e useEffect não é opcional.É algo praticamente cotidiano. Esses dois Hooks gerenciam a maior parte da lógica de estado e efeitos colaterais de qualquer aplicação moderna, desde um simples contador até interfaces complexas com requisições HTTP, assinaturas de eventos e animações.

O problema é que é muito fácil usá-los "a olho nu" e acabar com vazamentos de memória, renderizações infinitas ou efeitos que são acionados quando não deveriam.Neste artigo, vamos explicar de forma clara como usar corretamente o useState e, principalmente, o useEffect: o que eles fazem exatamente, como se relacionam com o ciclo de vida do componente, como gerenciar a limpeza de dependências, como otimizar o desempenho com o array de dependências e como aplicar padrões avançados sem quebrar a cabeça.

O que são Hooks e por que useState e useEffect são tão importantes?

Os Hooks surgiram no React 16.8 para permitir o uso de estado e outras funcionalidades sem a necessidade de classes.Em vez de estender de React.Component e lidando com métodos de ciclo de vida, trabalhamos com funções que chamam Hooks como useState y useEffect em seu interior.

useState é o Hook que fornece estado local dentro de um componente funcional.Ela retorna um valor e uma função para atualizá-lo, e cada vez que você atualiza esse estado, você aciona uma nova renderização do componente. É a base para tornar sua interface dinâmica: contadores, formulários, indicadores de carregamento, etc.

O useEffect, por outro lado, é o Hook que permite executar efeitos secundários após a renderização.Isso inclui elementos como solicitações de dados, assinaturas de websockets, ouvintes de DOM, temporizadores, integração com bibliotecas externas ou atualizações manuais do DOM quando não há outra opção.

Se você está acostumado com componentes de classe, pode ver o useEffect como a combinação de componentDidMount, componentDidUpdate e componentWillUnmount.mas agrupadas em uma única API declarativa. A ideia é pensar em termos de "efeitos que ocorrem após a renderização", em vez de fases separadas de "montagem" ou "atualização".

Como o useEffect funciona em um nível conceitual

A assinatura básica do useEffect é muito simples: useEffect(configuración, dependencias?)Você passa para ela uma função de configuração que será executada após o componente ser renderizado e, opcionalmente, uma lista de dependências que determina quando esse efeito deve ser repetido.

A função de configuração concentra a lógica do seu efeito: inscrever-se em algo, lançar uma solicitação, iniciar um intervalo, interagir com o DOM, etc. Essa função também pode retornar outra função de limpeza que o React executará quando for a hora de desfazer o que você fez: cancelar um intervalo de tempo, cancelar a inscrição, abortar uma solicitação, etc.

O segundo argumento de useEffect é o famoso array de dependências.Ali você precisa listar todos os valores "reativos" que usa dentro do efeito: props, state e quaisquer variáveis ​​ou funções definidas diretamente no corpo do componente. O React compara esse array com o da renderização anterior usando Object.isSe alguma dependência for alterada, remova o efeito antigo e execute o novo.

Se você não passar um array de dependências, o useEffect será executado após cada renderização.Se você passar um array vazio []O efeito é executado apenas uma vez durante a montagem e é eliminado durante a desmontagem, simulando o torque. componentDidMount / componentWillUnmountE se você passar dependências específicas, o efeito só será acionado quando um desses valores for alterado.

Primeiros passos: combinando useState e useEffect

Um exemplo clássico para entender a relação entre os dois Hooks é o contador típico que atualiza o título do documento.. com useState Você controla o número de cliques e com useEffect você muda document.title após cada renderização:

A chave é que useEffect é definido dentro do componente.Portanto, você pode ler diretamente o estado atual e as propriedades graças aos closures do JavaScript. Você não precisa de APIs especiais do React para acessar o estado dentro do efeito; tudo está dentro do escopo da função.

  Como obter imagens do Facebook no iPhone e Android

Além disso, o React não reutiliza a mesma função de efeito entre renderizações: você gera uma nova função a cada renderização.Isso é intencional: cada efeito está associado à renderização na qual foi criado e, quando o React detecta mudanças nas dependências, ele substitui um efeito por outro, limpando o anterior primeiro. Esse modelo facilita a compreensão de quais valores cada efeito vê em um determinado momento.

Outro detalhe importante é que os efeitos não bloqueiam a renderização da interface.O React primeiro atualiza o DOM e permite que o navegador renderize, e então executa. useEffectNa maioria dos casos (pedidos, torasetc.) Isso melhora a sensação de fluidez. Se você precisar fazer algo de forma síncrona pouco antes do usuário ver a tela (por exemplo, medir e reposicionar uma dica de ferramenta), então você deve usar useLayoutEffect, que compartilha a API, mas é executado antes da renderização.

Tipos de efeitos: com e sem limpeza

Nem todos os efeitos colaterais são iguais: alguns efeitos são executados e nada mais, enquanto outros exigem uma limpeza explícita.Distinguir entre esses dois tipos é fundamental para evitar deixar assuntos sem solução na memória ou comportamentos estranhos.

Os efeitos "no-clean" são aqueles em que você não deixa nada "aberto".Por exemplo, escrever no log, fazer uma requisição única e salvar o resultado no estado, iniciar uma animação autogerenciável ou fazer uma modificação única no DOM. Em termos de ciclo de vida, eles dependem apenas de componentDidMount / componentDidUpdate e não exigem nada em componentWillUnmount.

Um exemplo típico seria usar navigator.geolocation.getCurrentPosition uma vez que o componente tenha sido renderizadoVocê solicita a localização, atualiza o estado com a latitude e longitude, o React renderiza novamente e pronto. Você não deixa um ouvinte permanente, então não precisa limpar nada ao desmontar o componente.

Os efeitos de limpeza aparecem quando o componente está conectado de forma persistente a um sistema externo.Isso inclui assinaturas de websockets ou de uma API de chat, ouvintes de eventos DOM, intervalos repetitivos ou tempos limite, etc. Nesses casos, se você não limpar os recursos ao desmontar ou alterar dependências, acabará com vazamentos de memória ou comportamentos inesperados.

A maneira idiomática do React de lidar com essa limpeza é retornar uma função do efeito.Essa função será executada sempre que o efeito precisar ser "desmontado": quando o componente for removido do DOM ou quando as dependências mudarem e o efeito antigo precisar ser substituído pelo novo. Um exemplo típico é um contador com setInterval que é limpo com clearInterval no retorno do efeito.

useEffect aplicado a eventos globais e assinaturas

Um uso muito comum do useEffect é se inscrever em eventos globais do navegador.. Como resize do window o keydown do documentNesses casos, é necessário conectar-se ao evento ao configurar o componente e desconectar-se ao desmontá-lo para evitar o acúmulo de ouvintes.

O padrão é sempre o mesmo: você adiciona os ouvintes dentro do efeito e os remove na função de limpeza.Além disso, se você quiser que essa assinatura seja criada apenas uma vez, passe uma matriz de dependências vazia. [] para que não se repita em todas as versões.

Essa mesma abordagem se aplica a integrações com APIs externas, SDKs de terceiros ou qualquer sistema que force você a "conectar" enquanto o componente estiver visível.Você conecta na função de configuração do efeito e desconecta na função de limpeza, confiando que o React chamará ambas conforme necessário, à medida que as dependências mudarem.

No modo de desenvolvimento e com o Modo Estrito ativado, o React realiza uma configuração extra e uma etapa de limpeza logo após a montagem.É uma espécie de teste de estresse para garantir que sua lógica de limpeza realmente desfaça tudo o que a configuração faz. Se você notar comportamentos estranhos apenas em desenvolvimento, geralmente é porque sua limpeza não foi bem-sucedida.

Requisições HTTP e condições de corrida com useEffect

Outro cenário muito comum para o uso de useEffect é a realização de requisições HTTP quando alguma propriedade ou parte do estado é alterada.Por exemplo, carregar os dados de um usuário quando eles mudam. userId ou recuperar informações sobre um Pokémon quando o nome nos adereços for atualizado.

A ideia geral é: você define um efeito que aciona uma função assíncrona, atualiza o estado com os dados recebidos e especifica na matriz de dependências de quais valores essa solicitação depende.Se você só quer que ele dispare quando estiver andando de bicicleta, pule esta etapa. []Se você quiser que ele seja executado sempre que algo mudar, userId, você inclui userId na matriz.

  Guia completo para excluir a pasta Windows.old no Windows 11 sem erros

Um detalhe delicado é o que acontece se o componente for removido antes que a solicitação seja respondida.. Sim no then ou depois do await ligar para setState Com relação a um componente que não está mais montado, você pode encontrar avisos ou, pior ainda, atualizações de status sobre componentes zumbis.

Um padrão comum para evitar isso é usar um sinalizador interno (por exemplo, isMounted o ignore)Você define isso no efeito, você o coloca em prática. truee na função de limpeza você a configura para falseDentro da função assíncrona, imediatamente antes da chamada setState, você verifica se a bandeira ainda está acesa trueSe já for falseVocê ignora a atualização. Isso também ajuda a evitar condições de corrida, em que várias solicitações podem ser resolvidas em uma ordem diferente daquela em que foram enviadas.

Outra opção mais moderna é usar o AbortController, caso a API que você esteja utilizando o suporte.para que a função de limpeza chame abort() e a promessa do pedido é rejeitada sem qualquer tentativa de influenciar o Estado. Em qualquer caso, a lógica do cancelamento ou da ignorância das respostas deve ser inerente ao próprio efeito.

Múltiplas chamadas a useEffect no mesmo componente

Uma das vantagens dos Hooks é que eles permitem separar a lógica pelo que ela faz, e não pelo método do ciclo de vida em que ela precisa ser colocada.Não há limitações ao usar múltiplos useEffect em um único componente.

Isso significa que você pode ter um efeito para gerenciar o título do documento, outro para se inscrever em um bate-papo e outro para detectar um evento de rolagem.Cada um com suas próprias dependências e lógica de limpeza, o React os executará na ordem em que aparecem no componente.

Em comparação com as classes, onde muita lógica não relacionada acabava misturada nos mesmos métodos do ciclo de vida, os Hooks incentivam a divisão por responsabilidades.Um efeito = um propósito específico. Se um efeito começa a realizar várias funções diferentes, provavelmente é hora de dividi-lo em vários.

Esse padrão se torna ainda mais poderoso quando você encapsula esses efeitos em hooks personalizados. (por exemplo, useWindowSize, useChatStatusetc.), mas mesmo sem ir tão longe, você ganha legibilidade usando vários efeitos pequenos em vez de um gigantesco.

O conjunto de dependências: reatividade e desempenho.

A variedade de dependências é o que torna o useEffect poderoso e, ao mesmo tempo, a origem de muitas dores de cabeça.A regra geral é simples: todo valor reativo que você usar dentro do efeito deve aparecer nesse array. Valores reativos são props, state e variáveis ​​ou funções definidas dentro do componente.

Não se trata de "escolher" dependências para que o efeito seja menos executado, mas sim de descrever honestamente de quais valores a lógica do efeito depende.Se o linter de eslint-plugin-react-hooks Está configurado corretamente; ele irá alertá-lo quando você tiver esquecido algo ou adicionado algo desnecessário.

Se você deseja remover uma dependência, não o faz silenciando o aviso; faz isso alterando o código para que o valor deixe de ser reativo.Por exemplo, se você usar uma constante serverUrl Como ele nunca muda, você pode movê-lo para fora do corpo do componente. Dessa forma, ele deixa de ser um valor reativo e você pode removê-lo do array sem causar erros ao React.

Quando um efeito lê um valor reativo, normalmente você quer que ele reaja às suas mudanças.Isso significa adicioná-lo ao array. Mas às vezes você quer ler o valor "atual" de algo (como um carrinho de compras) sem que alterações nesse algo disparem o efeito novamente. Para esses casos, o React está introduzindo o conceito de "eventos de efeito" (como useEffectEvent), que encapsulam código não reativo capaz de ler o último valor sem se tornar uma dependência.

Para melhorar o desempenho, o padrão típico é restringir a matriz de dependências ao mínimo indispensável.Em vez de deixar o efeito sem um segundo argumento (o que o aciona após cada renderização), você passa um array contendo apenas os valores que realmente devem acioná-lo. Se nenhuma dependência for alterada entre as renderizações, o React ignora a limpeza e a configuração, e o efeito não é executado novamente.

  Métodos para excluir dados de cartão de crédito do iPhone

Solução de problemas comuns com o useEffect

Um dos erros mais comuns é acabar com um efeito que entra em um loop infinito.Isso geralmente acontece quando você atualiza um estado dentro do próprio efeito, um estado que faz parte do array de dependências. O efeito altera o estado, o estado aciona uma renderização, a renderização reexecuta o efeito e o ciclo recomeça.

Para quebrar esse ciclo, revise por que você está atualizando esse estado a partir do efeito.Se você não estiver sincronizando com um sistema externo, talvez nem precise do useEffect: muitas coisas podem ser tratadas diretamente no render. Se estiver sincronizando com algo externo, certifique-se de que a atualização do estado dependa apenas de mudanças reais e não seja acionada a cada vez.

Outra fonte comum de problemas são as dependências que mudam a cada renderização sem que você perceba.Criar objetos ou funções inline no JSX e usá-los no efeito sempre resultará em um array de dependências diferente, pois cada renderização gera uma nova referência. Para evitar isso, você pode mover a criação desses objetos para o próprio efeito ou, como último recurso, estabilizá-los com useMemo / useCallback.

Também é comum se surpreender ao ver que a função de limpeza é executada mesmo quando o componente ainda está na tela.Isso é normal: o React limpa o efeito anterior antes de aplicar o novo sempre que as dependências mudam. E em desenvolvimento, com o StrictMode ativado, ele também realiza um ciclo extra de configuração e limpeza logo após a montagem.

Por fim, se o seu efeito for visual e você notar uma oscilação antes de ele ser aplicado, verifique se há alguma diferença.Você pode precisar mudar para useLayoutEffect Para forçar a execução antes que o navegador renderize a página. É uma ferramenta para ser usada com moderação, somente quando você realmente precisar bloquear a renderização até que a medição ou o posicionamento estejam concluídos.

useEffect e renderização do lado do servidor (SSR)

Um detalhe importante em aplicações de renderização do lado do servidor é que os efeitos são executados apenas no cliente.Durante a renderização no servidor (SSR), o React gera o HTML inicial, mas não executa os efeitos. Estes são acionados posteriormente, quando o aplicativo é carregado no navegador.

Isso significa que qualquer lógica dentro de useEffect que dependa de APIs do navegador (como localStorage o window) é seguro contra o servidorPorque não será executado diretamente lá. O que você precisa garantir é que a primeira renderização (aquela feita no servidor e depois repetida no cliente) seja determinística e não leia nada que exista apenas no navegador.

Se você deseja exibir conteúdo diferente no servidor e no cliente, um padrão comum é usar um estado como didMountInicialmente está em false, e em um useEffect com [] você o coloca em trueEnquanto o valor for falso, você renderiza uma versão "segura" do componente; quando ele se tornar verdadeiro, você poderá lê-lo. localStorage, ajustar o DOM, etc. No entanto, tente garantir que a mudança visual não seja muito brusca para usuários com conexões lentas.

Em geral, quanto mais você tornar sua árvore de componentes independente do ambiente, menos surpresas terá ao combinar SSR com Hooks.Reserve o useEffect para a integração real com sistemas externos, que é para o que ele foi projetado.

Dominar useState e useEffect envolve internalizar que os componentes são "recriados" a cada renderização, que os efeitos pertencem a um ciclo de vida específico e que o array de dependências descreve a relação entre seu código e os dados reativos.Ao internalizar esse modelo mental, a sensação de magia negra desaparece e você começa a usar esses Hooks com facilidade, escrevendo componentes mais declarativos, limpos e fáceis de manter, mesmo em grandes aplicações React.