Skip to content

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:

  1. Uma função de efeito: O código que você deseja executar.
  2. 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?

  1. Sincronização com APIs externas: Fazer chamadas fetch quando um componente monta ou quando um ID muda (sempre via Sagas/Actions no nosso projeto).
  2. Assinaturas (Subscriptions): Configurar WebSockets ou listeners de eventos.
  3. Manipulação direta do DOM: Casos raros onde você precisa interagir com bibliotecas que não são do React.
  4. Timers: Configurar setTimeout ou setInterval.

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 key no componente. O React recriará o componente com o estado inicial automaticamente.
  • Sintaxe: No nosso projeto, não utilizamos arrow functions em useEffect ou definições de handlers. Use sempre function.