← React: componentes, estado e decisões de interface
06 / 10 · 60 MIN

Effects, refs e sincronização externa

Sincronizar subscrições com o ciclo de vida do componente, declarar dependências e usar refs sem esperar atualizações visuais automáticas.

Escolher entre cálculo, evento e sincronização

Nem todo o trabalho pertence a um Effect. Um nome completo derivado de dois campos pode ser calculado durante o render. Um envio que corresponde ao clique de confirmação pertence à lógica dessa interação.

Uma subscrição que deve existir enquanto o componente está ligado a um sistema externo é uma necessidade de sincronização. O exemplo acompanha a largura do viewport, que pode mudar independentemente dos eventos do formulário. Essa é a razão para o listener externo.

Antes de adicionar um Effect, descreve qual sistema está a ser sincronizado e qual condição deve fazer começar, atualizar ou terminar essa relação. Se só estás a copiar um valor derivável para outro estado, revê primeiro o modelo de dados.

Setup e cleanup como um par

O setup cria a relação externa e pode devolver uma função de cleanup. Quando mudam dependências após um commit, React executa o cleanup com os valores anteriores antes de estabelecer o novo setup. Ao remover a instância, executa também o cleanup correspondente.

No exemplo, measure é criado dentro do setup e a função devolvida remove esse mesmo listener. Registar um handler vazio adicional ou limpar apenas uma variável não liberta a subscrição anterior. Em ligações externas, o mesmo princípio exige fechar a ligação criada por aquele setup.

A unidade de análise é o recurso concreto, não apenas o nome da função que aparece no código.

Dependências que descrevem a lógica

A lista deve incluir os valores reativos usados pela lógica, como props e estado. React compara cada dependência com a anterior através de Object.is; não faz uma comparação profunda arbitrária de objetos. Omitir o segundo argumento pede nova execução após cada commit. [] declara que não há dependências reativas nessa lógica, não que ela deve ler valores novos sem voltar a executar.

No exemplo, o Effect usa window e um setter de identidade estável, sem ler width ou props. Se uma ligação passasse a depender de roomId, essa prop teria de participar na lista. Silenciar um aviso para conservar [] pode esconder uma ligação à sala antiga enquanto a interface já apresenta outra.

Objetos novos e religações evitáveis

Um objeto options criado no corpo do componente é novo em cada render, mesmo quando contém as mesmas strings. Se o Effect depende desse objeto, escrever noutro campo pode desencadear cleanup e nova ligação. Uma solução simples é construir options dentro do Effect e depender dos valores reativos que o compõem.

Se serverUrl for uma constante de módulo e roomId uma prop, a lista pode ser [roomId]. Se serverUrl passar a ser prop, também precisa de entrar na análise. A correção não é apagar indiscriminadamente dependências; é fazer a estrutura corresponder à configuração que realmente governa a ligação.

Refs para valores que não agendam render

useRef devolve um objeto estável para a instância, com uma propriedade current mutável. Mudar current não informa React de que deve renderizar. Por isso width é estado no exemplo, enquanto inputRef guarda a referência ao nó para uma ação imperativa.

Depois de o input ser criado, React associa o nó a current; ao removê-lo, current pode voltar a null. O handler de foco considera essa possibilidade. Não uses uma ref como substituição automática do estado visual nem leias e escrevas current durante o render para contornar pureza, exceto nos padrões de inicialização permitidos.

A escolha depende de se a mudança deve determinar a apresentação ou apenas conservar uma referência para uso posterior.

Desenvolvimento, remount e paint

Em Strict Mode, React pode exercitar um ciclo adicional de setup e cleanup em desenvolvimento para revelar problemas de simetria. Uma flag didRun pode reduzir mensagens no log sem fechar a ligação ao sair. Quando a página volta a montar, recursos antigos podem continuar ativos.

O objetivo é que setup, cleanup e novo setup deixem a relação correta. Também evita afirmar que useEffect corre sempre depois do paint: a documentação distingue Effects associados a interações e outros casos. Effects só correm no cliente, não na renderização do servidor.

O exemplo começa com uma apresentação sem medição e só consulta window dentro do Effect no cliente.

Diagnosticar recursos e observações

Perante callbacks duplicados, identifica quantas subscrições estão ativas e que cleanup deveria remover cada uma. Perante uma ligação antiga, compara as props lidas com a lista de dependências. Perante religações a cada tecla, procura objetos ou funções criados no render que mudam de identidade.

Estes são diagnósticos diferentes e não pedem todos uma ref ou []. Regista o estado antes e depois de montar, alterar configuração e sair. Os casos são modelos de decisão por leitura; não afirmam que um ensaio de browser tenha sido executado.

Pedidos assíncronos, resultados fora de ordem e Suspense terão limites próprios na aula seguinte.

import {useEffect, useRef, useState} from 'react';

export default function ViewportNote() {
  const [width, setWidth] = useState(null);
  const inputRef = useRef(null);
  useEffect(() => {
    function measure() { setWidth(window.innerWidth); }
    measure();
    window.addEventListener('resize', measure);
    return () => window.removeEventListener('resize', measure);
  }, []);
  function focusNote() { inputRef.current?.focus(); }
  return <section>
    <p>Viewport: {width === null ? 'Waiting for client measurement' : width}</p>
    <label>Local note <input ref={inputRef} name="note" /></label>
    <button type="button" onClick={focusNote}>Focus note</button>
  </section>;
}
NA PRÁTICA

O setup mede a largura no cliente e regista um listener. O cleanup remove exatamente esse listener. width é estado porque a apresentação deve reagir à medição; inputRef permite focar o nó montado num clique. [] é adequado aqui porque a lógica não lê props ou outro estado reativo.

Armadilhas comuns

Usar [] para esconder props usadas; depender de um objeto novo em cada render; usar uma flag para evitar setup sem cleanup; alterar uma ref e esperar render; garantir que todo o Effect corre depois do paint.

Tópicos relacionados: Eventos, snapshots de estado e filas de atualização · Reducers, contexto e estado partilhado · Dados assíncronos, Suspense e limites de erro

Leva esta ideia contigo

Effects sincronizam a interface com sistemas externos e precisam de dependências e cleanup coerentes. Refs retêm valores mutáveis sem agendar render. Usa estado para dados que devem determinar a apresentação.

Criar conta

Referência: Effect lifecycle and dependencies · React 19.3.0; JSX