useEffect
O useEffect é um Hook que permite executar efeitos colaterais em componentes funcionais. Ele é o substituto para os métodos de ciclo de vida como componentDidMount, componentDidUpdate e componentWillUnmount.
Como funciona?
O useEffect recebe dois argumentos:
- Uma função de efeito: O código que você deseja executar.
- Um array de dependências (opcional): Define quando o efeito deve ser re-executado.
javascript
useEffect(() => {
// Código do efeito
return () => {
// Função de limpeza (cleanup) - opcional
};
}, [dependencias]);Quando usar?
- Sincronização com APIs externas: Fazer chamadas fetch quando um componente monta ou quando um ID muda (sempre via Sagas/Actions no nosso projeto).
- Assinaturas (Subscriptions): Configurar WebSockets ou listeners de eventos.
- Manipulação direta do DOM: Casos raros onde você precisa interagir com bibliotecas que não são do React.
- Timers: Configurar
setTimeoutousetInterval.
Exemplo de Uso Correto:
javascript
function useTimer() {
const [seconds, setSeconds] = useState(0);
useEffect(function() {
const timer = setInterval(function() {
setSeconds(function(s) { return s + 1; });
}, 1000);
// Limpeza: evita vazamento de memória ao desmontar o componente
return function() {
clearInterval(timer);
};
}, []); // Executa apenas uma vez (montagem)
return seconds;
}Quando NÃO usar? (Onde as pessoas se perdem)
Muitas vezes o useEffect é usado desnecessariamente para sincronizar estados ou transformar dados. Se você pode calcular algo a partir das props ou do estado atual durante a renderização, não use useEffect.
1. Transformação de dados para renderização
Se o valor depende de outro estado, calcule-o diretamente.
❌ Como NÃO fazer (Ruim):
javascript
function PatientProfile({ patient }) {
const [fullName, setFullName] = useState('');
// RUIM: useEffect desnecessário para algo que já temos
useEffect(function() {
setFullName(patient.firstName + ' ' + patient.lastName);
}, [patient]);
return <h1>{fullName}</h1>;
}✅ Como fazer (Bom):
javascript
function PatientProfile({ patient }) {
// BOM: Calculado durante a renderização. Sem render adicional.
const fullName = patient.firstName + ' ' + patient.lastName;
return <h1>{fullName}</h1>;
}2. Cálculos caros (Use useMemo)
Se a transformação for pesada (ex: filtrar uma lista longa de consultas), use useMemo.
✅ Exemplo com useMemo:
javascript
function ConsultationHistory({ appointments, filter }) {
// BOM: Só recalcula se 'appointments' ou 'filter' mudarem
const filteredAppointments = useMemo(function() {
return appointments.filter(function(app) {
return app.status === filter;
});
}, [appointments, filter]);
return <List items={filteredAppointments} />;
}3. Lógica disparada por eventos
Não use useEffect para detectar que um estado mudou para então disparar uma ação. Use o próprio handler de evento.
❌ Como NÃO fazer (Ruim):
javascript
function AppointmentForm() {
const [isSaved, setIsSaved] = useState(false);
// RUIM: useEffect observando mudança de estado para disparar log
useEffect(function() {
if (isSaved) {
reportToSentry('Consulta Salva');
}
}, [isSaved]);
function handleSave() {
// ... lógica de salvar
setIsSaved(true);
}
return <button onClick={handleSave}>Salvar</button>;
}✅ Como fazer (Bom):
javascript
function AppointmentForm() {
function handleSave() {
// ... lógica de salvar
// BOM: Dispare o efeito colateral diretamente no evento que o causou
reportToSentry('Consulta Salva');
}
return <button onClick={handleSave}>Salvar</button>;
}Melhores Práticas e Anti-patterns
- Evite Cadeias de Efeitos: Se o Efeito A altera o Estado X, que dispara o Efeito B, seu código se torna imprevisível e difícil de depurar.
- Não use useEffect para "Resetar" estado: Se você precisa resetar o estado de um componente quando um ID muda (ex: trocar de paciente), use a prop
keyno componente. O React recriará o componente com o estado inicial automaticamente. - Sintaxe: No nosso projeto, não utilizamos arrow functions em
useEffectou definições de handlers. Use semprefunction.