From 82b6c6b333e8c017a76bbdc5871ad57f11003435 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 8 Sep 2026 09:47:31 +0200 Subject: [PATCH] Evita di calcolare le statistiche di tutta la rosa dove serve solo l'anagrafica MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LinkProfilo (header di ogni pagina) e il Calendario (compleanni del mese) usavano useIo/useRosa, che calcola MVP, pagelle, cacche, palloni e infortuni per l'intera squadra tramite 6 hook e un useMemo pesante - anche se a entrambi serviva solo id/nome/nascita/iniziali. Il Calendario in particolare pagava questo costo ad ogni apertura solo per i compleanni del mese. - crapp-data.ts: esporta inizialiDa, già usata internamente per il fallback avatar. - ui-bits.tsx: LinkProfilo usa useGiocatoreBase (sola anagrafica) invece di useIo. - rosa.ts: nuovo hook useAnagraficaRosa (id, nome, nascita) senza gli altri 5 hook statistici ne' il useMemo su tutta la rosa. - eventi.ts: compleanniEventi accetta solo i tre campi che usa, non l'intero Giocatore. - calendario.tsx: usa useAnagraficaRosa al posto di useRosa. Co-Authored-By: Claude Sonnet 5 --- src/components/crapp/ui-bits.tsx | 14 +++++++---- src/lib/crapp-data.ts | 3 ++- src/lib/eventi.ts | 14 +++++++++-- src/lib/rosa.ts | 17 ++++++++++++++ src/routes/calendario.tsx | 4 ++-- todo.md | 40 ++++++++++++++++++++++++++++++-- 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/components/crapp/ui-bits.tsx b/src/components/crapp/ui-bits.tsx index e2c2151..326fa85 100644 --- a/src/components/crapp/ui-bits.tsx +++ b/src/components/crapp/ui-bits.tsx @@ -2,8 +2,9 @@ import { useId, useState, type ComponentPropsWithoutRef, type ReactNode } from " import { Link } from "@tanstack/react-router"; import { ChevronDown } from "lucide-react"; import { cn } from "@/lib/utils"; -import { statoMeta, type Stato } from "@/lib/crapp-data"; -import { useIo } from "@/lib/rosa"; +import { inizialiDa, statoMeta, type Stato } from "@/lib/crapp-data"; +import { nomeCompleto } from "@/lib/giocatori-squadra"; +import { useGiocatoreBase } from "@/lib/user-store"; import { Avatar } from "@/components/crapp/Avatar"; import { Reveal } from "@/components/motion/Reveal"; import { Numero } from "@/components/motion/Numero"; @@ -51,9 +52,14 @@ export function Card({ * Accesso al profilo in alto a destra: la BottomNav ha quattro voci e questa è * l'unica porta verso `/profilo`. Sulla pagina del profilo si passa `azione` a * `PageHeader` per rimetterci il logo — sarebbe un link a sé stessa. + * + * Usa `useGiocatoreBase` (sola anagrafica) e non `useIo`: qui serve solo id e + * iniziali, mentre `useIo` calcola l'intera rosa con statistiche (MVP, pagelle, + * cacche, palloni, infortuni). Essendo in un componente montato su quasi ogni + * pagina, quei moduli finirebbero nel bundle condiviso di tutte le rotte. */ export function LinkProfilo() { - const g = useIo(); + const g = useGiocatoreBase(); if (!g) return ; return ( - + ); } diff --git a/src/lib/crapp-data.ts b/src/lib/crapp-data.ts index e5b36d3..3de2b53 100644 --- a/src/lib/crapp-data.ts +++ b/src/lib/crapp-data.ts @@ -73,7 +73,8 @@ const rosaCSI: Rosa[] = [ { nome: "Giada Valbonesi", nascita: "1994-05-20", ruolo: "Opposto", numero: 10 }, ]; -function inizialiDa(nome: string) { +/** Iniziali da un nome completo (max 2 lettere), es. per il fallback di `Avatar`. */ +export function inizialiDa(nome: string) { return nome .split(" ") .map((p) => p[0] ?? "") diff --git a/src/lib/eventi.ts b/src/lib/eventi.ts index 94564f7..cfe3ba9 100644 --- a/src/lib/eventi.ts +++ b/src/lib/eventi.ts @@ -162,8 +162,18 @@ export function useEliminaEvento() { }); } -/** Compleanni della rosa, come eventi di calendario dell'anno indicato. */ -export function compleanniEventi(rosa: Giocatore[], anno = new Date().getFullYear()): Evento[] { +/** + * Compleanni della rosa, come eventi di calendario dell'anno indicato. + * + * Prende solo i tre campi che usa (non l'intero `Giocatore`): il Calendario li + * legge da un'anagrafica leggera per non tirarsi dietro tutte le statistiche + * (MVP, pagelle, cacche, palloni, infortuni) di `useRosa` solo per le date di + * nascita. + */ +export function compleanniEventi( + rosa: Array>, + anno = new Date().getFullYear(), +): Evento[] { return rosa .filter((g) => g.nascita) .map((g) => { diff --git a/src/lib/rosa.ts b/src/lib/rosa.ts index 38b4df9..e8ceff3 100644 --- a/src/lib/rosa.ts +++ b/src/lib/rosa.ts @@ -24,6 +24,23 @@ function iniziali(nome: string, cognome: string): string { return `${nome[0] ?? ""}${cognome[0] ?? ""}`.toUpperCase(); } +/** + * Solo anagrafica (id, nome, data di nascita) dei giocatori attivi — es. per i + * compleanni nel Calendario. A differenza di `useRosa` non legge MVP, pagelle, + * cacche, palloni né infortuni: evita di montare quei cinque hook e il relativo + * `useMemo` solo per una data di nascita. + */ +export function useAnagraficaRosa(): Array> { + const { righe: squadra } = useGiocatoriSquadra(); + return useMemo( + () => + squadra + .filter((g) => g.attivo) + .map((g) => ({ id: g.id, nome: nomeCompleto(g), nascita: nascitaPerId[g.id] ?? "" })), + [squadra], + ); +} + /** * Rosa completa con tutte le statistiche personali (presenze, MVP, media voto, * palloni, infortuni, ritardi, cacche). Legge l'anagrafica da `giocatori_squadra` diff --git a/src/routes/calendario.tsx b/src/routes/calendario.tsx index 4b84651..4d508a3 100644 --- a/src/routes/calendario.tsx +++ b/src/routes/calendario.tsx @@ -9,7 +9,7 @@ import { useMotoRidotto } from "@/lib/motion"; import { EventoCard, linkPerEvento } from "@/components/crapp/EventoCard"; import { Card, PageHeader, Section } from "@/components/crapp/ui-bits"; import { compleanniEventi, useEventi, type Evento } from "@/lib/eventi"; -import { useRosa } from "@/lib/rosa"; +import { useAnagraficaRosa } from "@/lib/rosa"; import { useIsAdmin } from "@/lib/ruoli"; import { Drawer, @@ -115,7 +115,7 @@ function Calendario() { const [drawerAperto, setDrawerAperto] = useState(false); const admin = useIsAdmin(); const { eventi } = useEventi(); - const rosa = useRosa(); + const rosa = useAnagraficaRosa(); // `useMotoRidotto` copre anche i device deboli (RAM bassa), non solo // `prefers-reduced-motion`: disattiva anche lo swipe orizzontale tra mesi. const ridotto = useMotoRidotto(); diff --git a/todo.md b/todo.md index 6c15961..d43eae7 100644 --- a/todo.md +++ b/todo.md @@ -105,13 +105,49 @@ non c'è contenuto "nascosto" che viene ricalcolato inutilmente — non modifica precedente (c089d9e) e da allora orfana. Rimossa insieme ai suoi fallback; il commento che la citava come confronto per `.vetro` è stato aggiornato. +## 9. [x] `LinkProfilo` (header di ogni pagina) tirava dentro tutte le statistiche della rosa +— APPLICATA + +`ui-bits.tsx` (`LinkProfilo`, usato in `PageHeader` su quasi ogni rotta) usava `useIo`, che +internamente chiama `useRosa()`: quest'ultimo calcola l'**intera rosa arricchita** (voti MVP, +medie pagelle, statistiche cacche, turni palloni, infortuni/ritardi — 6 hook + un `useMemo` +pesante su tutta la squadra) solo per leggere `id` e iniziali di un giocatore. + +Fix: `LinkProfilo` ora usa `useGiocatoreBase` (`lib/user-store.ts`, sola anagrafica da +`giocatori_squadra`) e calcola le iniziali con `inizialiDa` (ora esportata da `crapp-data.ts`), +senza toccare gli altri moduli statistici. + +Verificato con build reale: le funzioni pesanti (`mediePagelle`, `statisticheCacche`, +`conteggioTurni`, `InfortuniERitardi`) sono sparite dal chunk `ui-bits`. **Attenzione**: la +dimensione totale del chunk non è cambiata (452KB) perché il grosso del peso è l'SDK Supabase +stesso, già necessario a monte in `__root.tsx` per il gate di login — non rimovibile da qui. +Il guadagno reale di questo fix è sul lavoro a runtime evitato (6 hook + memo in meno ad ogni +render dell'header), non sulla dimensione del bundle. + +## 10. [x] Aprire Calendario montava la stessa rosa "pesante" solo per i compleanni — APPLICATA + +`calendario.tsx` chiamava `useRosa()` (le stesse 6 statistiche del punto 9: MVP, pagelle, +cacche, palloni, infortuni/ritardi) ma usava il risultato **solo** per `compleanniEventi`, che +legge esclusivamente `id`, `nome` e `nascita`. Cliccare Calendario forzava quindi il calcolo (e, +la prima volta nella sessione, il fetch) di dati completamente estranei al calendario — probabile +causa diretta del lag "particolarmente su Calendario" segnalato. + +Fix: nuovo hook `useAnagraficaRosa` in `rosa.ts` — solo `useGiocatoriSquadra` + lookup statico +`nascitaPerId`, senza gli altri 5 hook né il `useMemo` pesante. `compleanniEventi` (`eventi.ts`) +accetta ora `Pick[]` invece dell'intero `Giocatore[]`, +riflettendo che è tutto ciò che usa. + ## Note - `useMotoRidotto` (`lib/motion.ts`) è ora l'heuristic condiviso di "device debole" usato in `BottomNav.tsx`, `BarraSottosezioni.tsx` e `calendario.tsx` (punti 2, 3, 6). Se si riprende il punto 4 (coriandoli), conviene usare lo stesso hook invece di un check separato. -- Applicati: 1, 2, 3, 6, 7. Restano da discutere/prioritizzare: 4 (coriandoli su device medi), - 5 (virtualizzazione liste lunghe). +- Applicati: 1, 2, 3, 6, 7, 8, 9, 10. Restano da discutere/prioritizzare: 4 (coriandoli su + device medi), 5 (virtualizzazione liste lunghe). +- Pattern ricorrente (punti 9, 10): `useRosa()` è comodo ma calcola *tutte* le statistiche della + squadra; usarlo solo per identità/anagrafica (id, nome, nascita, iniziali) costa 5-6 hook e un + `useMemo` su tutta la rosa inutilmente. Se in futuro emerge un altro caso simile, riusare + `useAnagraficaRosa` (o `useGiocatoreBase` per il singolo giocatore) invece di `useRosa`/`useIo`. - Se il lag persistesse ancora dopo questi fix, il prossimo passo è profilare un device Android reale (Chrome DevTools remoto o `chrome://inspect`) invece di continuare a ipotizzare: a questo punto le cause "ovvie" lette dal codice sono coperte, e senza un trace reale si rischia