Andrey Epifancev 045aa4ba18 docs(openspec): aurora-1839-cell-memo — пороги не блокируют слияние, замеры у контроллера
Решения 28.10: пороги производительности — цель, недобор в follow-up;
машина замеров Apple M4, пороги абсолютные; замеры выполняет контроллер
после ночного прогона; пустая полоса при перетаскивании по умолчанию
принимается как штатное поведение MRT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:41:09 +04:00

7.5 KiB
Raw Blame History

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: независима.