Skip to content

feat(utils): add getKey prop to <For> for stable list reconciliation#907

Merged
JoviDeCroock merged 2 commits intopreactjs:mainfrom
jbalsas:feat/for-getkey-prop
Mar 27, 2026
Merged

feat(utils): add getKey prop to <For> for stable list reconciliation#907
JoviDeCroock merged 2 commits intopreactjs:mainfrom
jbalsas:feat/for-getkey-prop

Conversation

@jbalsas
Copy link
Copy Markdown
Contributor

@jbalsas jbalsas commented Mar 27, 2026

Problem

The <For> component uses index-based keys on the internal <Item> wrapper, causing incorrect DOM reuse when items are removed or reordered — the classic React/Preact key problem.

Even when consumers set key={item.id} on their rendered children, the <Item> wrapper's key={index} overrides correct reconciliation.

Solution

Add an optional getKey prop to ForProps<T>:

interface ForProps<T> {
  each: Signal<Array<T>> | ReadonlySignal<Array<T>> | (() => ...);
  fallback?: ReactNode;
  getKey?: (item: T, index: number) => string | number;
  children: (value: T, index: number) => ReactNode;
}

When getKey is provided, its return value is used as the key prop on the internal <Item> component, giving React/Preact stable identity for reconciliation.

Usage

<For each={items} getKey={item => item.id}>
  {item => <p>{item.label}</p>}
</For>

Changes

  • packages/react/utils: Add getKey to ForProps, use it for <Item> key prop
  • packages/preact/utils: Same changes + adds the previously missing key prop on <Item>
  • Tests (both packages): Item removal, duplicate values, and reorder scenarios

Backward compatibility

getKey is optional — omitting it preserves existing behavior (index-based keys).

The <For> component uses index-based keys on the internal <Item> wrapper,
causing incorrect DOM reuse when items are removed or reordered (the classic
React/Preact key problem).

Add an optional getKey prop to ForProps that lets consumers provide stable
identity keys derived from item data (e.g., getKey={item => item.id}).

When getKey is provided, its return value is used as the component key on
<Item>. When omitted, behavior is unchanged (index-based keys).

Changes:
- packages/react/utils: add getKey to ForProps, use it for <Item> key prop
- packages/preact/utils: same, also adds previously missing key prop on <Item>
- tests for both packages: removal, duplicates, reorder scenarios
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 27, 2026

🦋 Changeset detected

Latest commit: c128f77

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for preact-signals-demo ready!

Name Link
🔨 Latest commit c128f77
🔍 Latest deploy log https://app.netlify.com/projects/preact-signals-demo/deploys/69c6667d45f1500008a4a37e
😎 Deploy Preview https://deploy-preview-907--preact-signals-demo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@JoviDeCroock JoviDeCroock merged commit 904a879 into preactjs:main Mar 27, 2026
6 checks passed
@github-actions github-actions bot mentioned this pull request Mar 27, 2026
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.

2 participants