This React warning appears when rendering arrays or lists without assigning unique key props to each element. Keys help React identify which items have changed, been added, or removed, enabling efficient re-rendering and preventing UI bugs.
This warning is React's way of telling you that when rendering an array of elements, each element needs a unique identifier called a "key" prop. Keys are essential for React's reconciliation algorithm, which determines how to efficiently update the DOM when your component re-renders. When React re-renders a list, it compares the new list with the previous one to figure out what changed. Without keys, React relies on the position of elements in the array to track them. This can lead to serious bugs: if items get reordered, React might think an element just changed its content when it actually moved positions, causing internal state, focus, or form values to be applied to the wrong elements. Keys act as stable identifiers that persist across renders, allowing React to accurately track which specific element is which, regardless of position changes. This ensures that component state, DOM state (like focus or scroll position), and side effects remain correctly associated with their intended elements.
Look at the file and line number mentioned in the console warning. Find where you're using .map(), .forEach(), or any loop that renders JSX elements. The warning points directly to the problematic list rendering location.
// Example of code causing the warning:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li>{user.name}</li> // Missing key prop here
))}
</ul>
);
}If your data comes from a database or API, use the unique ID from your data source. This is the best practice because these IDs remain stable across renders and uniquely identify each item.
// Fixed with database ID:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}For objects without IDs, consider adding unique identifiers when you create or fetch the data.
If your data doesn't have unique IDs, generate them when the data is first created (not during render). Use crypto.randomUUID() in modern browsers or a library like uuid for older environments.
import { v4 as uuidv4 } from 'uuid';
// Generate IDs when creating data, not during render:
const items = [
{ id: uuidv4(), text: 'Item 1' },
{ id: uuidv4(), text: 'Item 2' }
];
function ItemList({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}Never generate new random keys during render, as this defeats the purpose and causes performance issues.
If your list will never reorder, filter, or change in any way, using the array index as a key is acceptable. However, this should be a last resort.
// Only use index for completely static lists:
function StaticMenu() {
const menuItems = ['Home', 'About', 'Contact']; // Never changes
return (
<nav>
{menuItems.map((item, index) => (
<a key={index} href={`/${item.toLowerCase()}`}>
{item}
</a>
))}
</nav>
);
}Avoid index keys if the list can be reordered, filtered, or have items added/removed.
When returning multiple elements for each item in a loop, you need to wrap them in a fragment and assign the key to the fragment, not to internal elements.
import { Fragment } from 'react';
function DefinitionList({ terms }) {
return (
<dl>
{terms.map(term => (
<Fragment key={term.id}>
<dt>{term.word}</dt>
<dd>{term.definition}</dd>
</Fragment>
))}
</dl>
);
}
// Or use the shorthand syntax:
function DefinitionList({ terms }) {
return (
<dl>
{terms.map(term => (
<React.Fragment key={term.id}>
<dt>{term.word}</dt>
<dd>{term.definition}</dd>
</React.Fragment>
))}
</dl>
);
}Note: The short <></> syntax doesn't support keys; you must use <Fragment> or <React.Fragment>.
Check that the keys you're using are actually unique within the same array. Duplicate keys will cause rendering issues even if they're present.
// Bad: Non-unique keys
function CategoryList({ items }) {
return items.map(item => (
<div key={item.category}> {/* Multiple items may share category */}
{item.name}
</div>
));
}
// Good: Unique composite key or unique ID
function CategoryList({ items }) {
return items.map(item => (
<div key={`${item.category}-${item.id}`}>
{item.name}
</div>
));
}Keys only need to be unique among siblings in the same array, not globally across your entire app.
After adding keys, refresh your app and check the browser console to confirm the warning is gone. Also test any interactive behavior with your list:
1. Open the browser console (F12 or Cmd+Option+I)
2. Clear any existing messages
3. Interact with your list (if it supports reordering, filtering, etc.)
4. Verify no key-related warnings appear
5. Test that component state persists correctly when list items move
If you still see the warning, double-check that every element returned from .map() has a key prop at the top level.
Keys are not passed as props to your components - React uses them internally for reconciliation. If you need the key value inside your component, pass it as a separate prop: <Component key={item.id} id={item.id} />.
In React 18 and later, the warning detection has been improved to catch more edge cases, including when keys are spread from props objects. When using TypeScript, the key prop is automatically excluded from prop spreading to prevent this issue.
For lists with thousands of items, consider virtualization libraries like react-window or react-virtual, which handle keys automatically while rendering only visible items for better performance.
In production builds, React suppresses this warning, but the underlying bugs (like incorrect state assignment during reordering) will still occur. Always fix key warnings during development.
When working with nested lists, each level of nesting needs its own set of unique keys. Keys don't need to be globally unique - only unique among siblings at the same nesting level.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite