Skip to content

frontend: use stable keys for channel and version lists - #1557

Open
archiik04 wants to merge 1 commit into
flatcar:mainfrom
archiik04:fix/328-stable-list-keys
Open

frontend: use stable keys for channel and version lists#1557
archiik04 wants to merge 1 commit into
flatcar:mainfrom
archiik04:fix/328-stable-list-keys

Conversation

@archiik04

@archiik04 archiik04 commented Aug 11, 2026

Copy link
Copy Markdown

Issue #328 asked whether each use of an array index as a React key is intended and safe. I went through all ten occurrences. Three had a stable identifier already in scope and now key on it:

  • VersionBreakdownBar keyed <Bar> by index while dataKey was already the version string.
  • Packages/Item now keys channel labels on channel.id.
  • ApplicationItemChannelsList mapped channels twice and keyed both by index. The second map only received a ReactNode, so it had no access to the channel; collapsing to a single map is what makes keying on channel.id possible. That also drops an if (channels) branch which was always true, since channels is defaulted to [] above it.

I left the rest alone:

  • Tabs: the index is the identity. It is also passed as index and to a11yProps.
  • ListHeader, MoreMenu, Instances/Charts: static lists that never reorder.
  • TimelineChart: also index-keyed, but it is in scope for Revisit chart animation on extended group view #407, which someone else is already working on. I stayed out of it.

SimpleTable is the one place where this could actually mis-associate rows, since it keys rows by index over paginated data. Its instances prop is typed any[] and neither caller supplies an id, so a correct fix needs either a key derived from the row's column values (which assumes no two rows are ever identical) or a new getRowKey prop. Both felt like a separate discussion, so I kept it out. Happy to take it on if you have a preference. I've used Refs #328 rather than Fixes for that reason.

Testing

npx tsc -b, npx eslint --max-warnings 0, and npx vitest run (79 tests, 20 files) all pass.

I did not add tests. None of the existing tests would have failed before this change either, since these lists do not currently reorder and there is no observable behaviour change today. A test that proved key stability would have to assert DOM node identity across a reorder, which seemed more brittle than valuable. If you'd rather have one, say so and I'll add it.

Issue flatcar#328 asked whether each use of an array index as a React key is
intended and safe. Three of the ten occurrences had a stable identifier
already in scope, so they now key on that instead:

- VersionBreakdownBar keyed <Bar> by index while dataKey was already the
  version string.
- Packages/Item now keys channel labels on channel.id.
- ApplicationItemChannelsList mapped channels twice and keyed both by
  index. Collapsing to a single map allows keying on channel.id, and
  drops an "if (channels)" branch that was always true because channels
  is defaulted to an empty array above it.

The rest are left alone. Tabs uses the index as the identity and passes
it to a11yProps. ListHeader, MoreMenu and Instances/Charts render static
lists that do not reorder. TimelineChart is also index-keyed but is in
scope for flatcar#407.

SimpleTable keys rows by index over paginated data, which is the one
place this could actually mis-associate rows. Its instances prop is
untyped and neither caller supplies an id, so a correct fix needs a
derived key or a new prop; that is left for a separate change.

No behaviour changes today, since none of these lists currently reorder.

Refs flatcar#328

Signed-off-by: Archi Kanungo <archi.kanungo2004@gmail.com>
@archiik04
archiik04 requested a review from a team as a code owner August 11, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant