DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Fixing “Each Child in a List Should Have a Unique `key` Prop” in React 19

Fixing “Each Child in a List Should Have a Unique  raw `key` endraw  Prop” in React 19

Fixing “Each Child in a List Should Have a Unique key Prop” in React 19

A forensic look at keys, reconciliation, and bullet‑proof patterns for dynamic routes & lists.


The Console Scream 😱

Warning: Each child in a list should have a unique "key" prop.
Check the render method of `AppRouter`. …
Enter fullscreen mode Exit fullscreen mode

1 Why React Cares About Keys

Without key With key
React reuses DOM nodes by index React reuses nodes by identity
Moving / filtering items can leak state (inputs swap, animations glitch) Stable identity → predictable diff

Keys act as the virtual DOM’s primary key.


2 Bug Anatomy

{routes.map(r => (
  <Route path={r} element={<Page name={r} />} />  // 🔥 missing key
))}
Enter fullscreen mode Exit fullscreen mode

Array item rendered without a key prop triggers the warning.


3 Three Golden Rules

  1. Key must be stable across renders
  2. Key must be unique among siblings
  3. Never use array index unless list is truly static

4 Fixing Dynamic <Route> Lists

{routes.map(r => (
  <Route key={r} path={r} element={<Page name={r} />} />
))}
Enter fullscreen mode Exit fullscreen mode

If objects contain IDs:

routeList.map(({ id, path, element }) => (
  <Route key={id} path={path} element={element} />
));
Enter fullscreen mode Exit fullscreen mode

5 Keys for Common UI Patterns

Pattern Key suggestion
DB rows row.id
Tabs (i18n) \${locale}-\${tabId}
Drag‑and‑drop list item.id
Skeleton placeholders "skeleton-\${i}" (static order)
File‑system routes File path / slug

6 Advanced Tips

Composite keys

key={`${userId}:${permission}`}
Enter fullscreen mode Exit fullscreen mode

Memoised rows

const Row = memo(({ item }: { item: Item }) => );
items.map(i => <Row key={i.id} item={i} />)
Enter fullscreen mode Exit fullscreen mode

Keys with useDeferredValue

Keep keys on original data array, not the deferred copy.


7 Testing & Linting

  • ESLint rule react/jsx-key (auto‑fix).
  • Jest snapshot diff catches DOM swaps.
  • E2E tests assert order after drag actions.

8 Real‑World AppRouter Fix

export const AppRouter = () => {
  const routes = [
    { id: 'home',     path: '/',         el: <HomePage /> },
    { id: 'projects', path: '/projects', el: <ProjectPage /> },
    { id: 'settings', path: '/settings', el: <SettingsPage /> },
  ];

  return (
    <Routes>
      {routes.map(({ id, path, el }) => (
        <Route key={id} path={path} element={el} />
      ))}
    </Routes>
  );
};
Enter fullscreen mode Exit fullscreen mode

✅ No warnings, ready for feature‑flag re‑ordering.


9 Cheat‑Sheet

Mistake Fix
key={index} on dynamic list key={item.id}
Missing key on mapped elements Provide slug/ID
Random Math.random() key Generates new key each render
Duplicate keys Use composite values

Final Thoughts

Keys are tiny but crucial. For every .map() ask:

  1. Unique?
  2. Stable?

✍️ Written by: Cristian Sifuentes – Full-stack dev crafting scalable apps with [NET - Azure], [Angular - React], Git, SQL & extensions. Clean code, dark themes, atomic commits

Follow those and your console will stay silent. Happy rendering! 🗝️🚀

Top comments (1)

Collapse
 
sharmaricky profile image
VS

This is very basic concept in React but one of the important ones.