(low) Cadastre jobs: React-key на внутреннем <tr> вместо mapped Fragment — нестабильная reconciliation / key-warning #1380

Closed
opened 2026-06-14 18:10:03 +00:00 by bot-backend · 0 comments
Collaborator

Описание

Коллбэк jobs.data.map(...) возвращает голый Fragment (<>...</>), детьми которого являются строка <tr> плюс условно-рендеримая строка развёрнутой панели. React требует key на верхнеуровневом элементе, возвращаемом коллбэком — здесь это Fragment, но key стоит на внутреннем <tr> (key={job.job_id}). Shorthand <> не принимает props, поэтому key игнорируется: React считает каждый Fragment unkeyed, выдаёт warning «Each child in a list should have a unique key» и откатывается на index-based reconciliation. Список refetch'ится каждые 5с (refetchInterval: 5000), строки переупорядочиваются/вставляются при смене статуса → index-based reconciliation может ассоциировать развёрнутую панель с НЕ той строкой и вызывать лишние remount'ы детали. Импортов Fragment из react нет (строка 3 — только named imports).

Корень

Key размещён на внутреннем <tr>, а не на возвращаемом из map Fragment; shorthand <> не может нести key.

Evidence

/Users/anton/Птица/gendesign/frontend/src/app/admin/scrape/cadastre/page.tsx:773-863

{jobs.data?.map((job) => (
  <>
    <tr
      key={job.job_id}
      ...
      onClick={() => toggleExpand(job.job_id)}
    >
      ...
    </tr>
    {expandedId === job.job_id &&
      renderExpandedPanel(...)}
  </>
))}

Suggested fix

Импортировать Fragment из React и ставить key на сам Fragment: {jobs.data?.map((job) => (<Fragment key={job.job_id}><tr ...>...</tr>{expandedId === job.job_id && renderExpandedPanel(...)}</Fragment>))} — key с внутреннего <tr> убрать.

Обоснование severity

Low: UI-корректность, без потери данных и security-импакта; warning + возможное лишнее перемонтирование/ошибочная ассоциация развёрнутой панели при переупорядочивании строк (активно каждые 5с).


week ревью 1 · multi-agent аудит 2026-06-14 · severity=low · category=correctness

Затронутые файлы:

  • /Users/anton/Птица/gendesign/frontend/src/app/admin/scrape/cadastre/page.tsx
## Описание Коллбэк `jobs.data.map(...)` возвращает голый Fragment (`<>...</>`), детьми которого являются строка `<tr>` плюс условно-рендеримая строка развёрнутой панели. React требует key на верхнеуровневом элементе, возвращаемом коллбэком — здесь это Fragment, но key стоит на внутреннем `<tr>` (`key={job.job_id}`). Shorthand `<>` не принимает props, поэтому key игнорируется: React считает каждый Fragment unkeyed, выдаёт warning «Each child in a list should have a unique key» и откатывается на index-based reconciliation. Список refetch'ится каждые 5с (`refetchInterval: 5000`), строки переупорядочиваются/вставляются при смене статуса → index-based reconciliation может ассоциировать развёрнутую панель с НЕ той строкой и вызывать лишние remount'ы детали. Импортов `Fragment` из react нет (строка 3 — только named imports). ## Корень Key размещён на внутреннем `<tr>`, а не на возвращаемом из map Fragment; shorthand `<>` не может нести key. ## Evidence `/Users/anton/Птица/gendesign/frontend/src/app/admin/scrape/cadastre/page.tsx:773-863` ```tsx {jobs.data?.map((job) => ( <> <tr key={job.job_id} ... onClick={() => toggleExpand(job.job_id)} > ... </tr> {expandedId === job.job_id && renderExpandedPanel(...)} </> ))} ``` ## Suggested fix Импортировать `Fragment` из React и ставить key на сам Fragment: `{jobs.data?.map((job) => (<Fragment key={job.job_id}><tr ...>...</tr>{expandedId === job.job_id && renderExpandedPanel(...)}</Fragment>))}` — key с внутреннего `<tr>` убрать. ## Обоснование severity Low: UI-корректность, без потери данных и security-импакта; warning + возможное лишнее перемонтирование/ошибочная ассоциация развёрнутой панели при переупорядочивании строк (активно каждые 5с). --- _week ревью 1 · multi-agent аудит 2026-06-14 · severity=**low** · category=`correctness`_ Затронутые файлы: - `/Users/anton/Птица/gendesign/frontend/src/app/admin/scrape/cadastre/page.tsx`
bot-backend added the
week ревью 1
label 2026-06-14 18:10:03 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:01:55 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1380
No description provided.