useEffect
Efeitos colaterais e ciclo de vida
useEffect é o hook para sincronizar um componente com sistemas externos: APIs, localStorage, WebSocket, timers, assinaturas. Ele roda depois que o componente renderizou no DOM e recebe uma função de efeito e um array de dependências.
O array de dependências controla quando o efeito roda: array vazio [] → roda apenas no mount (montagem); com valores [a, b] → roda no mount e toda vez que a ou b mudar; sem array → roda após cada re-render (raramente o que você quer). A função pode retornar outra função de cleanup que o React chama antes do próximo efeito ou ao desmontar o componente.
Erros comuns: esquecer dependências (o efeito usa uma variável mas não a lista — acessa valor desatualizado), criar loops infinitos (o efeito muda um estado que está nas dependências), e não limpar assinaturas/timers (vazamentos de memória).
import { useState, useEffect } from "react";
// ── Buscar dados de uma API ───────────────────────
function Usuarios() {
const [usuarios, setUsuarios] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelado = false; // evita atualização após unmount
async function buscar() {
try {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const data = await res.json();
if (!cancelado) setUsuarios(data);
} finally {
if (!cancelado) setLoading(false);
}
}
buscar();
return () => { cancelado = true; }; // cleanup
}, []); // [] = roda só no mount
if (loading) return <p>Carregando...</p>;
return <ul>{usuarios.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
// ── Sincronizar com localStorage ──────────────────
function Tema() {
const [tema, setTema] = useState(
() => localStorage.getItem("tema") ?? "dark" // inicialização lazy
);
useEffect(() => {
localStorage.setItem("tema", tema);
document.documentElement.dataset.tema = tema;
}, [tema]); // roda toda vez que tema mudar
return <button onClick={() => setTema(t => t === "dark" ? "light" : "dark")}>
{tema}
</button>;
}
// ── Timer com cleanup ─────────────────────────────
function Relogio() {
const [tempo, setTempo] = useState(new Date());
useEffect(() => {
const id = setInterval(() => setTempo(new Date()), 1000);
return () => clearInterval(id); // ← cleanup essencial!
}, []);
return <p>{tempo.toLocaleTimeString()}</p>;
}Se o efeito busca dados, crie uma variável de cancelamento ou use AbortController para evitar atualizar o estado de um componente desmontado. React 18 strict mode monta/desmonta componentes duas vezes em dev para detectar esses problemas.