10 — Render cost: virtualização ausente, memoização e re-render
Pergunta: mesmo com TTFB resolvido, o frame de pintura aguenta 2k linhas? Onde React re-renderiza além do necessário?
Evidência
rg "react-window|react-virtual"emsrc/→ zero matches. A plataforma não usa nenhuma técnica de virtualização hoje.resultados-lista.tsx(747 LoC) renderiza a tabela completa retornada pelo backend. ComfetchAllRowsdrenando 2k linhas, são 2k×N nós DOM por mount.- Listas equivalentes em risco:
mensagens_enviadas(timeline coord),alunos(gestão),inscricoes_olimpiada(subscrição em massa),logs_transacoes(admin-logs).
Por que isso virou problema só agora
Antes do fix do incidente Nível S, a query truncava em 1000 silenciosamente — a renderização também ficava capada. Com fetchAllRows, o DOM cresce na proporção real. Render cost virou tão relevante quanto fetch cost.
Onde virtualização é mandatória (proposta)
| Componente | Cardinalidade | Estratégia recomendada |
|---|---|---|
resultados-lista tabela | até 8k linhas/olimpíada | @tanstack/react-virtual em <tbody> |
Timeline mensagens_enviadas | crescente sem teto | virtual + paginação cursor por created_at |
admin-logs table | crescente sem teto | virtual + paginação cursor |
gestao-alunos lista | 5k–10k em escolas grandes | virtual + filtro server-side |
Nota: ao virar paginação servidor (F1), virtualização só é necessária se o
pageSizeainda for ≥200. ParapageSize=50(sugerido) o DOM cabe sem virtualizar — prefira F1 antes de virtualizar.
Re-render gaps a auditar
useMemo/useCallbackemresultados-lista.tsx: derivarlinhasfiltradas/ordenadas dentro deuseMemo([dados, filtros]), não em loose body.- Lista de itens deve receber
keyestável (UUID, não índice). <Select>/ dropdowns com 1k opções (séries, alunos) — confirmarComboboxvirtual em vez de<SelectItem>plano.- Toda mutação que atualiza UMA linha não deve forçar refetch da lista inteira (usar
setQueryDatapara patch otimista — cf.mem://architecture/optimistic-updates-standard).
Hipóteses
- H1: Mesmo após F1 (paginação servidor) com
pageSize=50, a tabela vai aguentar sem virtualização. - H2: A timeline de mensagens e admin-logs vão precisar de virtualização independentemente da paginação (UX de scroll infinito).
- H3: Re-renderização em filtros (digitação no input de busca) é responsável por parte do "travado" percebido — investigar
debounceemonChangeantes de atribuir à query.
Próximas etapas (auditoria, não fix)
- Medir com
browser--performance_profilena tela Resultados antes e depois de F1. - Identificar todos os componentes que renderizam
>200itens via.map()direto. - Adicionar regra no 99: lista >300 linhas requer virtualização ou paginação servidor.