Решения 28.10: пороги производительности — цель, недобор в follow-up; машина замеров Apple M4, пороги абсолютные; замеры выполняет контроллер после ночного прогона; пустая полоса при перетаскивании по умолчанию принимается как штатное поведение MRT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
7.5 KiB
Markdown
61 lines
7.5 KiB
Markdown
# Proposal: мемоизация ячеек таблицы листа (AURORA-1839, Gitea #234)
|
||
|
||
## Why
|
||
|
||
Скролл листа формы — главная жалоба заказчика (perf/REPORT.md, М1). До цепочки P1 шаг колеса 200 px на FORM_2/AHR стоил 89,0 мс главного потока (масштаб 1, rf, CPU 1×, медиана; `perf/report-data/20261026-s1/summary.md`). На профилирующей сборке это 3,3 коммита React и 14,8 тыс. рендеров компонентов на шаг, из них 1 696 `Styled(td)` (`analysis/hotspots.md`). Все ~500 видимых ячеек перерисовываются при каждом коммите. Дорого не собственная ячейка `Cell` (она в `React.memo`), а обёртка material-react-table: `MRT_TableBodyCell` → `TableCell` → `Styled(td)`.
|
||
|
||
AURORA-1836 убрала чтение layout в `measureElement`, AURORA-1837 перенесла статичные стили ячеек в CSS контейнера. Обе задачи удешевили одну перерисовку ячейки, но не уменьшили число перерисовок. Число перерисовок сокращает только мемоизация ячеек MRT (`memoMode: 'cells'`). Без неё критерий эпика AURORA-1834 (≤ 25 мс на шаг) недостижим.
|
||
|
||
С мемоизацией появляется риск устаревшего вида ячеек. MRT сравнивает только идентичность объекта `cell`, поэтому состояние вне данных строки (закрепление колонок, фильтры) нужно явно доносить до ячеек. Это ограничение распространяется на все будущие правки таблицы (AURORA-1889, 1890, 1891, 1893, 1910), поэтому его нужно записать как контракт.
|
||
|
||
## What Changes
|
||
|
||
- Таблица листа (`RealtimeTable`) включает мемоизацию ячеек MRT (`memoMode: 'cells'`). Ячейки, которые остаются на экране при прокрутке, не перерисовываются.
|
||
- Мемоизация сбрасывается явно, новым массивом колонок таблицы:
|
||
- при изменении раскладки закреплённых колонок: закрепление, открепление, скрытие или показ закреплённой колонки, смена её ширины;
|
||
- при изменении глобального поиска и фильтров по колонкам.
|
||
|
||
Сброс не полагается на побочные эффекты MRT и `filterFromLeafRows`.
|
||
- Ширина закреплённой колонки сбрасывает мемоизацию один раз, по отпусканию мыши. Пока колонку тянут, соседние закреплённые колонки могут отставать. Ширина незакреплённых колонок меняется через CSS-переменные MRT, их скрытие и показ мемоизацию не сбрасывают.
|
||
- Собственное перетаскивание ширины в заголовке (`TableHead`/`ColumnResizer`) начинает сообщать MRT о начале и конце перетаскивания (`columnSizingInfo.isResizingColumn`). Фильтры по колонкам становятся управляемым состоянием `RealtimeTable`.
|
||
- Записывается контракт для всех будущих правок таблицы:
|
||
- рендер ячейки зависит только от объекта `cell`;
|
||
- остальное состояние передаётся через CSS по атрибутам, контекст или хранилище с подпиской;
|
||
- обработчики читают актуальное состояние через `ref` или `table.getState()`.
|
||
- Добавляются node-тесты ключа сброса и допущения о пересоздании ячеек в `@tanstack/table-core`.
|
||
- В стенд `perf/e2e` добавляется сценарий «закрепить колонку и потянуть её ширину — время кадра».
|
||
- Пороги производительности (≤ 25 мс на шаг и др.) — цель, а не условие слияния. PR вливается по зелёным тестам и ручному регрессу, цифры замеров (контроллер, Apple M4) дописываются в PR. Недобор — follow-up issue с разбором. Корректность — жёсткое условие.
|
||
- Поведение для пользователя не меняется: поиск, фильтры, ошибки валидации, блокировки соавторов, выделение строки, редактирование, разрядность и закрепление работают как раньше.
|
||
|
||
## Не меняется
|
||
|
||
- Своды 1 и 2 (`SummaryTable.jsx`, `Svod2Page.jsx`) и их конфигурации MRT — это М2 и М6, отдельные задачи.
|
||
- Цена рендера при входящей правке соавтора. Новый массив `data` пересоздаёт все строки и ячейки, мемоизация тут не помогает. Это область AURORA-1838.
|
||
- Собственный компонент `Cell.jsx` и его стили: их правят AURORA-1890, 1892 и 1894.
|
||
- Backend, SQL и миграции.
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
- `sheet-table`: таблица листа формы (`RealtimeTable`):
|
||
- производительность прокрутки;
|
||
- корректность закреплённых колонок, подсветок и состояния ячеек при мемоизации;
|
||
- контракт для правок таблицы.
|
||
|
||
### Modified Capabilities
|
||
Нет: `openspec/specs/` пуст.
|
||
|
||
## Impact
|
||
|
||
- Код: `web/src/components/RealtimeTable/`:
|
||
- `RealtimeTable.jsx`: `memoMode`, ключ сброса, управляемые `columnFilters` и `columnSizingInfo`;
|
||
- `TableHead/TableHead.jsx`, `TableHead/ColumnResizer.jsx`: начало и конец перетаскивания;
|
||
- новый модуль ключа сброса в `utils/` и тесты к нему.
|
||
- Стенд: новый сценарий `perf/e2e/scenarios/pinned-resize.spec.ts`. Добавляется после ночного прогона, отдельным коммитом.
|
||
- Зависимости не меняются. `material-react-table` 3.2.1 зафиксирован в `web/package-lock.json`. Поведение MRT, на которое опирается дизайн, сверено с этой версией (см. design.md).
|
||
- Стек PR: ветка `feat/234-aurora-1839-cell-memo` от `feat/226-aurora-1837-cell-styles-css` (AURORA-1837, PR #230). Та, в свою очередь, стоит на AURORA-1836 (PR #222).
|
||
- Связи:
|
||
- AURORA-1838: связанная, не блокирующая;
|
||
- AURORA-1889, 1890, 1891, 1893, 1910: обязаны соблюдать контракт из `specs/sheet-table/spec.md`;
|
||
- AURORA-1840: независима.
|