Memoizar a lista filtrada, os totais e os cartões de processo - #81
Merged
Merged
Conversation
O `filtered`, o `stats`, o `throughput30` e as médias de lead/cycle time eram
recalculados a cada render do `App` — incluindo a cada tecla escrita na caixa de
pesquisa. Por processo, o filtro chama o `calcStatus` até quatro vezes e a
ordenação chama o `procOverallPct`, que percorre todas as fases e passos dos
dois percursos; os totais são mais oito varrimentos da lista, que dependem só do
`procs` e nada tinham a ver com o que estava a ser escrito.
· os quatro passam a `useMemo`, com as dependências que o
`react-hooks/exhaustive-deps` valida (já estava ligado no lint);
· o `ProcessCard` passa a `React.memo`. É o que se multiplica pela lista e
cada cartão chama o `procOverallPct` e o `calcStatus` ao desenhar-se. O
`onClick` que recebe já era o `setSelected` — um setter de estado, estável
entre renders —, pelo que a comparação de props não é anulada por uma
função nova a cada render;
· a pesquisa passa pelo `useDeferredValue`: a caixa responde à tecla e a
lista é refeita logo a seguir, em vez de as duas coisas competirem pelo
mesmo frame.
O `isDone`, o `isLate` e o `roleStatus` sobem para o nível do módulo, como
`isProcDone` (que já lá estava), `isProcLate` e `procRoleStatus`. Não dependiam
de estado nenhum, e uma função recriada a cada render entra nas dependências do
`useMemo` e fá-lo recalcular sempre — que é o mesmo que não o ter.
O `Date.now()` do throughput passou para dentro do `useMemo`, pelo que o "agora"
é o do último `procs` e não o de cada render. A janela é de 30 dias: umas horas
de diferença numa página deixada aberta não mudam nenhum número.
Os 760 objectos `style={{…}}` ficam como estão. Objectos literais em props só
custam quando o filho é memoizado, e o único que passou a sê-lo recebe apenas
`proc` e `onClick`. Extraí-los todos seria um diff enorme com risco visual e
ganho nulo.
O `tests/harness.mjs` ganha `memo` e `useDeferredValue` no seu React de
mentira: ao contrário dos hooks, o `memo` é chamado na avaliação do módulo
(`const X = React.memo(…)`) e sem ele o bloco JSX rebentava antes de definir
seja o que for.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XwDMNpJzcA3Z2nP3jjwuJd
qzte
marked this pull request as ready for review
September 14, 2026 20:43
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ponto #9 do plano de melhorias.
O que era recalculado a cada tecla
O
filtered, ostats, othroughput30e as médias de lead/cycle time viviam no corpo doAppe eram refeitos a cada render — incluindo a cada tecla escrita na caixa de pesquisa, e a cada render provocado por qualquer outro estado.Por processo, o filtro chama o
calcStatusaté quatro vezes e a ordenação chama oprocOverallPct, que percorre todas as fases e passos dos dois percursos. Os totais são mais oito varrimentos da lista — e dependem só doprocs, nada tendo a ver com o que está a ser escrito.O que muda
useMemo, com as dependências que oreact-hooks/exhaustive-depsvalida (já estava ligado no lint, portanto isto é verificado e não prometido).ProcessCardpassa aReact.memo. É o que se multiplica pela lista, e cada cartão chama oprocOverallPcte ocalcStatusdos dois percursos ao desenhar-se. OonClickque recebe já era osetSelected— um setter de estado, estável entre renders —, pelo que a comparação de props não é anulada por uma função nova a cada render. Trocá-lo por uma arrow inline anula a memoização toda; fica escrito no código.useDeferredValue: a caixa responde à tecla e a lista é refeita logo a seguir, em vez de as duas coisas competirem pelo mesmo frame.isDone, oisLatee oroleStatussobem para o nível do módulo (isProcDone, que já lá estava,isProcLate,procRoleStatus). Não dependiam de estado nenhum, e uma função recriada a cada render entra nas dependências douseMemoe fá-lo recalcular sempre — que é o mesmo que não o ter.Medição, não estimativa
Com um backup gerado pela própria aplicação e carregado pelo «📂 Carregar backup», a escrever «Cardiologia» (11 teclas) na pesquisa. Sete repetições por célula, mediana, Chromium headless:
main— escrita / lista estabilizaA 300 processos é 2,3× mais rápido. A 800 a diferença é marginal (~7%) — aí o que domina é desenhar os cartões que realmente mudaram, e isso a memoização não remove. A dispersão das amostras a 800 também é grande (175–682 ms), pelo que esse número deve ser lido como «não piorou», não como ganho.
O backup actual tem 0 processos, portanto hoje nada disto se nota. É trabalho preventivo, e é a razão de o ter medido em vez de o afirmar.
O que deliberadamente não foi feito
Os 760 objectos
style={{…}}ficam como estão. Objectos literais em props só custam quando o filho é memoizado, e o único que passou a sê-lo recebe apenasproceonClick. Extraí-los todos seria um diff enorme, com risco visual real e ganho nulo.Nota sobre o
Date.now()O «agora» do throughput passou para dentro do
useMemo, pelo que é o do últimoprocse não o de cada render. A janela é de 30 dias: umas horas de diferença numa página deixada aberta não mudam nenhum dos números, e a gravação seguinte refaz a conta. Fica comentado no código.Testes
npm run cipassa (86 unitários, lint, validate, build). Nos testes de browser, 62 passam e as 11 falhas são oERR_CERT_AUTHORITY_INVALIDdo proxy TLS deste ambiente — o mesmo resultado, teste a teste, que antes desta alteração.O
tests/harness.mjsganhoumemoeuseDeferredValueno seu React de mentira: ao contrário dos hooks, omemoé chamado na avaliação do módulo (const X = React.memo(…)) e sem ele o bloco JSX rebentava antes de definir seja o que for.🤖 Generated with Claude Code
https://claude.ai/code/session_01XwDMNpJzcA3Z2nP3jjwuJd
Generated by Claude Code