home / skills / flpbalada / my-opencode-config / react-key-prop
This skill helps you apply correct key prop usage in React lists by promoting stable, unique IDs and highlighting when to avoid index keys.
npx playbooks add skill flpbalada/my-opencode-config --skill react-key-propReview the files below or copy the command above to add this skill to your agents.
---
name: react-key-prop
description: Guides proper usage of the key prop in React lists. Use this skill when rendering lists, mapping arrays to components, or troubleshooting list-related state bugs.
---
# React: Key Prop Best Practices
## Core Principle
**Use stable, unique IDs from your data. Never use array index for dynamic lists.**
The `key` prop provides stable identity to list elements during React's reconciliation process.
## When to Use What
### Use Data IDs (Preferred)
Always use unique, stable identifiers directly from your data:
```jsx
// ✅ Correct
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
```
Ideal keys are:
- **Unique** - No two items share the same key
- **Stable** - Never changes during component lifetime
- **Predictable** - Directly tied to the data item
### Generate IDs on Data Load
When data lacks IDs, create them **once** when receiving data:
```jsx
import { nanoid } from 'nanoid';
useEffect(() => {
fetch('/api/items')
.then(res => res.json())
.then(data => {
const itemsWithIds = data.map(item => ({
...item,
_tempId: nanoid() // Stable ID generated once
}));
setItems(itemsWithIds);
});
}, []);
```
### When Index Is Acceptable (Rare)
Index as key is acceptable ONLY when ALL conditions are met:
- List is absolutely static
- Items never added/removed (except at the end)
- Order never changes
- Items have no internal state
## Anti-Patterns to Avoid
### Never Generate Keys During Render
```jsx
// ❌ WRONG: Creates new key every render
{items.map(item => (
<li key={Math.random()}>{item.name}</li>
))}
```
This forces React to destroy and recreate all components on every render.
### Don't Use Index for Dynamic Lists
```jsx
// ❌ WRONG for dynamic lists
{items.map((item, index) => (
<li key={index}>{item.name}</li>
))}
```
Index fails when:
- Items are added/removed from beginning or middle
- List order changes (sorting, filtering)
- Items have internal state (like form inputs)
**The bug:** Index represents position, not data identity. When positions change but indexes stay the same, React incorrectly "mutates" existing components instead of creating new ones, causing state mismatch.
### Don't Use `useId()` for List Keys
React's `useId()` hook is for accessibility (linking labels to inputs), not for generating list keys.
## Quick Reference
### DO
- Always use `key` when rendering lists
- Prefer unique, stable `id` from your data
- Generate IDs once at data load time (`nanoid`/`uuid`)
### DON'T
- Never generate `key` during render (`Math.random()`, `Date.now()`)
- Avoid `index` as `key` for dynamic lists
- Don't use `useId()` for list keys
## References
- [React Docs - Rendering Lists](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key)
- [nanoid - Tiny ID generator](https://github.com/ai-cookie/nanoid)
This skill guides correct usage of React's key prop when rendering lists and mapping arrays to components. It focuses on choosing stable, unique identifiers, avoiding common anti-patterns, and preventing list-related state bugs. Use it to enforce reliable reconciliation and predictable UI updates.
The skill inspects list rendering patterns and recommends appropriate keys based on data shape and mutation patterns. It highlights safe strategies (use data IDs, generate IDs once at load) and flags risky patterns (index keys for dynamic lists, keys generated every render). It explains the reconciliation consequences so developers can fix state mismatches and unnecessary re-renders.
Why is using array index as key bad?
Index ties identity to position; when items are inserted, removed, or reordered, indexes change and React may reuse the wrong component instance, causing state and UI mismatches.
What do I do if my data has no IDs?
Generate stable IDs once when you receive or normalize the data (store them on each item). Use libraries like nanoid or uuid so keys remain constant across renders.
Is useId() a valid key generator for lists?
No. useId() is for accessibility IDs and can collide or change across renders; it is not intended to provide stable list identity.