Hook useEffect
Sincronize um componente com um sistema externo executando efeitos colaterais após a renderização.
Busque em todas as páginas da documentação
Sincronize um componente com um sistema externo executando efeitos colaterais após a renderização.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
// Executa após cada renderização
useEffect(() => {
console.log("renderizado");
});
// Executa uma vez ao montar
useEffect(() => {
fetchData();
}, []);
// Executa quando as dependências mudam
useEffect(() => {
document.title = `Você clicou ${count} vezes`;
}, [count]);
// Limpeza ao desmontar ou antes de reexecutar
useEffect(() => {
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []);Quando usar isso: Você precisa sincronizar com algo fora do React - buscar dados, assinar eventos, manipular o DOM ou configurar timers.
"use client";
import { useEffect, useState } from "react";
export function WindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
function handleResize() {
setSize({ width: window.innerWidth, height: window.innerHeight });
}
handleResize(); // Define o tamanho inicial
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return (
<p className="text-sm font-mono">
Janela: {size.width} × {size.height}
</p>
);
}O que isso demonstra:
resize) dentro do useEffect[] para que o efeito seja executado apenas uma vez ao montaruseEffect executa após o navegador pintar a tela, não durante a renderização.| Parâmetro | Tipo | Descrição |
|---|---|---|
setup | () => void ou () => () => void | Função de efeito; opcionalmente retorna uma função de limpeza |
dependencies | unknown[] ou omitido | Array de valores reativos dos quais o efeito depende |
| Retorno | Tipo | Descrição |
|---|---|---|
| (nenhum) | void | useEffect não retorna um valor |
Busca de dados com limpeza (controlador de abortar):
useEffect(() => {
const controller = new AbortController();
async function load() {
const res = await fetch(`/api/users/${id}`, {
signal: controller.signal,
});
const data = await res.json();
setUser(data);
}
load();
return () => controller.abort();
}, [id]);Conectando a um WebSocket:
useEffect(() => {
const ws = new WebSocket(url);
ws.onmessage = (e) => setMessages((prev) => [...prev, JSON.parse(e.data)]);
return () => ws.close();
}, [url]);Sincronizando com localStorage:
useEffect(() => {
localStorage.setItem("theme", theme);
}, [theme]);// Efeito com async - deve envolver porque useEffect não pode retornar uma Promise
useEffect(() => {
async function fetchData() {
const res = await fetch("/api/data");
const json: DataType = await res.json();
setData(json);
}
fetchData();
}, []);
// TypeScript detecta automaticamente tipos de retorno de limpeza ausentesLoop infinito - Atualizar um estado que também é uma dependência faz com que o efeito seja executado indefinidamente. Correção: Restrinja seu array de dependências ou mova a atualização do estado para trás de uma condição.
Dependências ausentes - Omitir um valor do array de dependências causa dados obsoletos dentro do efeito. Correção: Inclua todos os valores reativos usados dentro do efeito, ou refatore para remover a dependência.
Async diretamente em useEffect - Retornar uma Promise em vez de uma função de limpeza produz um aviso do React. Correção: Defina uma função async dentro do efeito e chame-a imediatamente.
Condições de corrida em re-renderizações rápidas - Se id mudar rapidamente, um fetch mais antigo pode resolver após um mais novo e sobrescrever dados corretos. Correção: Use um AbortController ou um flag booleano ignore na limpeza.
Executando no servidor - useEffect não executa durante SSR. Acessar window ou document sem proteção causa erros de build. Correção: Acesse APIs do navegador apenas dentro do useEffect ou atrás de uma verificação typeof window !== "undefined".
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
useLayoutEffect | Você precisa medir ou mutar o DOM antes que o navegador pinte | O efeito não toca no layout ou DOM visual |
| Manipulador de eventos | O efeito colateral é acionado por uma ação específica do usuário (clique, envio) | O efeito deve ser executado ao montar ou quando um valor muda |
fetch de Componente de Servidor | Os dados podem ser buscados no momento da requisição no servidor | Os dados dependem do estado do lado do cliente ou da interação do usuário |
useSyncExternalStore | Assinando uma store externa (Redux, API do navegador) | Configuração única ou busca de dados |
Por que não buscar em useEffect? Para muitos aplicativos, frameworks como Next.js oferecem busca de dados no lado do servidor que evita spinners de carregamento e waterfalls. Reserve a busca do useEffect para necessidades de dados puramente do lado do cliente.
De uma aplicação SaaS de produção Next.js 15 / React 19 (SystemsArchitect.io).
// Exemplo de produção: Navegação por teclado para cartões de estudo
// Arquivo: src/hooks/use-card-keyboard.ts
import { useEffect } from "react";
interface UseCardKeyboardOptions {
isAutoplayOn: boolean;
cardNumber: number;
totalCards: number;
hasMoreCards: boolean;
onCardClick: () => void;
onNext: () => void;
onPrev: () => void;
}
export function useCardKeyboard({
isAutoplayOn, cardNumber, totalCards, hasMoreCards,
onCardClick, onNext, onPrev,
}: UseCardKeyboardOptions) {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (isAutoplayOn) return;
if (event.code === "Space" || event.key === " ") {
event.preventDefault();
onCardClick();
} else if (event.key === "ArrowLeft" || event.key === "a") {
event.preventDefault();
if (cardNumber > 1) onPrev();
} else if (event.key === "ArrowRight" || event.key === "d") {
event.preventDefault();
if (cardNumber < totalCards || hasMoreCards) onNext();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [cardNumber, totalCards, hasMoreCards, isAutoplayOn, onCardClick, onNext, onPrev]);
}O que isso demonstra em produção:
keydown ao desmontar e sempre que as dependências mudam, evitando o acúmulo de manipuladores obsoletos.cardNumber) causaria bugs de closure obsoleta onde valores antigos são capturados.onCardClick, onNext e onPrev devem ser envolvidas em useCallback pelo componente pai. Sem isso, cada re-renderização do pai cria novas referências de função, fazendo com que este efeito desinscreva e reinscreva o listener desnecessariamente.isAutoplayOn no topo do manipulador é um padrão de produção para desabilitar a entrada do teclado durante a reprodução automática sem remover o listener completamente.useEffect(() => { ... }, []) executa uma vez ao montar e limpa ao desmontar.useEffect(() => { ... }) executa após cada renderização.useEffect espera que o callback retorne undefined ou uma função de limpeza.async retorna uma Promise, que o React não pode usar como função de limpeza.useEffect(() => {
async function fetchData() {
const res = await fetch("/api/data");
setData(await res.json());
}
fetchData();
}, []);AbortController para cancelar a requisição anterior quando as dependências mudarem.ignore definido como true na função de limpeza.useEffect(() => {
const controller = new AbortController();
fetch(`/api/users/${id}`, { signal: controller.signal })
.then(res => res.json())
.then(setUser);
return () => controller.abort();
}, [id]);useEffect quando precisar sincronizar com um sistema externo ao montar ou quando uma dependência mudar.Object.is, que verifica a igualdade de referência.{} ou array [] criado durante a renderização tem uma nova referência a cada vez.useMemo ou extraindo dependências primitivas.useEffect((): (() => void) => {
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []);
// TypeScript infere o tipo de limpeza automaticamente
// na maioria dos casos - tipagem explícita raramente é necessária.useEffect só executa no cliente, então window e document estão sempre disponíveis dentro dele.useEffect durante a renderização do lado do servidor.useEffect ou atrás de uma guarda typeof window !== "undefined".useEffect executa após o navegador pintar a tela (assíncrono).useLayoutEffect executa síncronamente após mutações do DOM, mas antes que o navegador pinte.useLayoutEffect apenas quando precisar medir ou mutar o DOM antes que o usuário o veja (por exemplo, tooltips, animações).Revisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥