Memoização não congela componentes
memo devolve uma versão do componente que pode evitar trabalho quando as props são equivalentes. Por omissão, compara cada prop com Object.is. Não faz uma comparação profunda ilimitada e não garante ausência absoluta de render.
Estado próprio e contexto consumido continuam a poder atualizar o componente. No exemplo, Results recebe um snapshot de rows e uma string query. Se o pai construir um array novo a cada render, essa identidade também entra na decisão.
Antes de acrescentar memo, identifica a origem do trabalho e os valores que realmente mudam. Uma aplicação correta deve continuar correta quando React decide voltar a renderizar.
Cache de um cálculo puro
useMemo pode reutilizar o resultado de um cálculo quando as dependências não mudam. filterRows deve continuar puro e a lista deve incluir todos os valores reativos usados. No exemplo, o filtro depende de rows e query. Omitir query conserva resultados antigos em vez de otimizar corretamente.
React pode descartar a cache, incluindo quando um componente suspende na montagem inicial. Por isso uma escolha do utilizador que precisa de ser conservada não deve depender exclusivamente dessa cache. Guarda o facto em estado e deriva resultados a partir dele.
Não mutar os dados e poder recalcular são condições de correção; o ganho de desempenho precisa de evidência própria.
Comparadores também preservam comportamento
Um arePropsEqual personalizado só deve declarar equivalência quando a saída e o comportamento continuarão equivalentes. Funções também são props: um onSelect novo pode capturar outro id ou outro estado do pai. Se o comparador ignorar essa mudança, a interface pode manter uma ação que usa dados antigos apesar de o texto parecer igual.
Também mede o custo da comparação. Percorrer profundamente uma estrutura crescente pode custar mais do que o render que se pretende evitar. A revisão precisa de dois resultados: comportamento preservado e trabalho total reduzido.
Contar apenas chamadas evitadas não estabelece nenhum dos dois de forma suficiente.
Transições marcam atualizações
startTransition chama a função fornecida imediatamente e marca as atualizações abrangidas como transições. Não coloca automaticamente uma computação síncrona pesada num Web Worker nem a transforma num timer. O trabalho de renderização de uma transição pode ser interrompido por atualizações mais urgentes, como a edição de texto.
O estado que controla o input deve continuar imediato. Na versão documentada, um setter depois de await precisa de outro startTransition para receber essa marcação. Uma chamada num timer também não herda automaticamente o âmbito anterior.
Analisa o local efetivo da atualização e evita inferir prioridade a partir do nome de uma função.
Apresentar um valor adiado
useDeferredValue permite que uma parte da interface use um valor anterior enquanto se prepara trabalho com o valor novo. No exemplo, query controla o input e deferredQuery alimenta Results. A mensagem Updating results torna explícito que a lista pode estar atrasada em relação ao texto.
Não existe um atraso fixo próprio do Hook como num debounce configurado com um intervalo. O trabalho em segundo plano é interrompível. O Hook também não impede, por si, pedidos extra de rede.
Se o produto precisa de cache, cancelamento ou limitação de frequência, esses contratos devem ser definidos na camada que inicia os pedidos.
Prioridade não decide a ordem lógica
Duas Actions assíncronas podem terminar por ordem inversa àquela em que começaram. Marcar atualizações como transições não informa automaticamente React sobre qual resposta representa a intenção mais recente. A documentação identifica esse limite através da fronteira assíncrona.
A aplicação precisa de uma abstração apropriada ou de uma política explícita de ordenação e aceitação. Por exemplo, a identidade da tentativa pode determinar se ainda é válido mostrar um resultado, conforme a aula anterior. Não confundas manter o input responsivo com preservar a ordem de operações num serviço. São objetivos distintos que podem exigir mecanismos distintos.
Medir e justificar a escolha
Uma proposta de otimização deve identificar o cenário, o trabalho medido e o comportamento que permanece correto. Compara custo antes e depois em condições representativas e modo de produção, pois verificações de desenvolvimento podem acrescentar chamadas.
Para um comparador, inclui o próprio custo da comparação; para um filtro, inclui tamanho e frequência de mudança dos dados. O pequeno exemplo desta aula demonstra a separação de responsabilidades, não um ganho medido. Na avaliação, escolhe a evidência que permitiria sustentar a decisão e reconhece o que a observação não cobre.
Uma cache ou transição só é útil quando melhora o percurso real sem conservar resultados ou ações incorretos.
import {memo, useDeferredValue, useMemo, useState} from 'react';
const Results = memo(function Results({rows, query}) {
const visible = useMemo(() => {
const text = query.toLowerCase();
return rows.filter(row => row.title.toLowerCase().includes(text));
}, [rows, query]);
return <ul>{visible.map(row => <li key={row.id}>{row.title}</li>)}</ul>;
});
// rows is an immutable snapshot with stable unique IDs and string titles.
export default function SearchReview({rows}) {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const stale = query !== deferredQuery;
return <section>
<label>Search <input value={query}
onChange={event => setQuery(event.target.value)} /></label>
<p>{stale ? 'Updating results...' : `Results for: ${deferredQuery}`}</p>
<Results rows={rows} query={deferredQuery} />
</section>;
}O input segue query imediatamente. Results recebe deferredQuery e pode continuar a apresentar o valor anterior enquanto o novo trabalho é preparado. O cálculo usa rows e query sem mutação. O exemplo é local e ilustrativo: não demonstra ganhos medidos nem reduz pedidos de rede.
Armadilhas comuns
Tratar memo como congelamento; depender de useMemo para guardar decisões; ignorar funções num comparador; usar transições para controlar texto; confundir useDeferredValue com debounce ou com cancelamento; presumir ordem de pedidos após await.
Tópicos relacionados: Reducers, contexto e estado partilhado · Dados assíncronos, Suspense e limites de erro · Testar comportamentos e delimitar a evidência
Otimiza trabalho observado e conserva o contrato funcional. Memoização pode reutilizar resultados; transições e valores adiados alteram prioridade. Nenhum destes mecanismos substitui estado persistente, política de rede ou aceitação de resultados.
Referência: Memo comparison and guarantees · React 19.3.0; JSX