Grille : remonter le corps du tableau au changement de colonnes

Le repli du bloc mensuel ne repeignait toujours pas les lignes déjà
montées : l'en-tête perdait ses douze colonnes, le corps les gardait, et il
fallait recharger la page pour retrouver une grille cohérente.

Le signal passé aux lignes (`columnsKey`) reposait sur la comparaison de
props de `React.memo`. La clé du `<tbody>` porte désormais cette même
signature : un changement de colonnes remonte le corps, sans plus dépendre
d'une comparaison qu'une prop oubliée suffit à mettre en défaut. Le
mécanisme existait déjà pour la densité d'affichage.

Le coût est celui des seules lignes virtualisées (une trentaine), et le
redimensionnement d'une colonne ne déclenche rien : les identifiants de
colonnes, eux, ne changent pas.

Vérifié cette fois sur un BUILD DE PRODUCTION, 2 000 lignes : au repli,
17 en-têtes et 17 cellules pour chaque ligne montée ; toujours 17 après
défilement vers des lignes virtualisées ensuite ; 29 partout au retour, et
17 au repli suivant — sans rechargement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYGgoQCG1VCe42HzbzhAXR
This commit is contained in:
Claude committed 2026-08-13 19:15:15 +00:00
1 parent c532386385
commit 0a2bc8318b
1 file changed
+11 -1
+11 -1
View File
@@ -1062,7 +1062,17 @@ export function HeatmapGrid({ onSelectionChange, isAdmin }: HeatmapGridProps) {
</tr>
))}
</thead>
<tbody key={displayDensity} style={{ height: rowVirtualizer.getTotalSize(), position: "relative", display: "block" }}>
{/*
* La clé porte AUSSI la signature des colonnes : changer de jeu de
* colonnes remonte le corps du tableau au lieu de compter sur la
* comparaison de props de `React.memo`. Une ligne mémoïsée qui rate
* le signal continue de peindre l'ancien jeu de cellules, et la
* grille se retrouve à deux vitesses — en-tête à jour, corps en
* retard. Un remontage ne coûte que les ~30 lignes virtualisées, et
* le redimensionnement (continu) ne le déclenche pas : les
* identifiants de colonnes ne changent pas.
*/}
<tbody key={`${displayDensity}|${columnsKey}`} style={{ height: rowVirtualizer.getTotalSize(), position: "relative", display: "block" }}>
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const row = tableRows[virtualRow.index];
const isSelected = row.getIsSelected();