Diego Betto
React 19

Diego Betto · October 12, 2026 · 4 min di lettura

React 19: the "A props object containing a key prop is being spread into JSX" warning

Why React 19 now warns when key ends up inside a spread props object, and how to destructure it out explicitly to fix it.

Condividi:XLinkedInFacebookWhatsApp

If you’ve just upgraded to React 19 and started seeing this warning somewhere you didn’t touch key directly, it’s worth understanding rather than dismissing:

⛔ Warning

A props object containing a “key” prop is being spread into JSX: <Component {…props} />. React keys must be passed directly to JSX without using spread. Learn more about keys: https://react.dev/link/warning-keys

This is new to React 19 — earlier versions silently swallowed key when it ended up inside a spread object, which hid a real bug instead of surfacing it. Understanding why key is special explains the fix.

Why key can never travel through a spread

key isn’t a regular prop. React strips it out of the props object before your component ever sees it — it’s metadata React itself uses to track list items across re-renders, not something your component logic is meant to read via props.key. That distinction matters here:

function List({ items }) {
  return items.map((item) => {
    const itemProps = { key: item.id, label: item.label };
    // key is inside itemProps here — but React needs it on the JSX call itself,
    // not buried inside a spread object
    return <Item {...itemProps} />;
  });
}

React reads key while processing the <Item ... /> call, not by inspecting the final props object your component receives — so a key hidden inside ...itemProps never reaches the place React actually looks for it. In earlier React versions this silently produced list items without a working key (defeating React’s reconciliation for that list); React 19 makes the mistake visible instead.

The fix: destructure key out explicitly

function List({ items }) {
  return items.map((item) => {
    const { key, ...itemProps } = { key: item.id, label: item.label };
    return <Item key={key} {...itemProps} />;
  });
}

Or, more directly, just skip building an intermediate object with key in it and pass key on the JSX element the normal way:

function List({ items }) {
  return items.map((item) => <Item key={item.id} label={item.label} />);
}

Where this sneaks in: forwarding props from a parent

The other common trigger is a component that receives a key-shaped prop from an API response or a data structure and spreads the whole object down without thinking about it:

function Row({ rowData }) {
  // rowData came from an API and happens to have a `key` field for its own reasons
  return <Cell {...rowData} />;
}

If rowData.key was never meant to be a React key at all — just a data field that happens to share the name — rename it before spreading, or destructure it out:

function Row({ rowData }) {
  const { key, ...cellProps } = rowData;
  return <Cell {...cellProps} data-row-key={key} />;
}

💡 Consiglio

If your data genuinely comes with a field called key for unrelated reasons (a database column, an external API field), that’s a naming collision worth resolving at the data layer if you can — it’ll keep tripping this warning (and confusing future readers) every time that object gets spread into JSX.

FAQ

❓ Was this a silent bug in React 18 and earlier?

Yes — key buried inside a spread object was silently dropped rather than applied, so list items rendered without React actually tracking them by the intended key. It often “worked” only by accident, relying on React’s fallback of using array index as an implicit key.

❓ Does this affect performance, not just correctness?

Both. A missing or index-based key can cause React to unnecessarily remount components on reorder (losing local state, re-running effects) instead of reusing the existing DOM node — the exact problem key exists to prevent.

❓ Can I still spread other props alongside an explicit key?

Yes, and this is the standard, correct pattern: <Item key={item.id} {...otherProps} /> — key passed directly, everything else spread. The warning only fires when key itself is part of what gets spread.

Conclusion

React 19 turns a bug that used to fail silently — key swallowed by a spread — into a warning you can actually act on. The fix is always the same shape: pass key directly on the JSX element, never as part of an object you spread with {...props}, and rename any unrelated data field that happens to collide with the name key before it reaches your JSX.

References

Condividi:XLinkedInFacebookWhatsApp
Diego Betto

Written by

Diego Betto

Co-Founder & CTO at PAPION. Senior full-stack engineer specializing in React, TypeScript, Node.js, and application security.