Last Updated: 3/9/2026
React
Best practices for using Nano ID in React applications.
Quick Summary
❌ Don’t use nanoid() for React keys
✅ Use stable IDs from your data
✅ Use React’s useId() for linking elements
The Key Problem
❌ Wrong: Generating Keys on Render
import { nanoid } from 'nanoid'
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={nanoid()}> {/* ❌ BAD: New ID every render */}
{todo.text}
</li>
))}
</ul>
)
}Problems:
- New ID generated on every render
- React treats items as different on each render
- Loses component state (focus, scroll position, etc.)
- Terrible performance (full re-render every time)
- Animations break
✅ Correct: Stable IDs from Data
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}> {/* ✅ GOOD: Stable ID from data */}
{todo.text}
</li>
))}
</ul>
)
}Benefits:
- Same ID across renders
- React correctly identifies items
- Preserves component state
- Good performance
- Animations work correctly
When to Use Nano ID in React
✅ Generating IDs When Creating Data
import { nanoid } from 'nanoid'
import { useState } from 'react'
function TodoApp() {
const [todos, setTodos] = useState([])
const addTodo = (text) => {
const newTodo = {
id: nanoid(), // ✅ Generate once when creating
text,
completed: false
}
setTodos([...todos, newTodo])
}
return (
<>
<AddTodoForm onAdd={addTodo} />
<ul>
{todos.map(todo => (
<li key={todo.id}> {/* ✅ Use stable ID */}
{todo.text}
</li>
))}
</ul>
</>
)
}✅ Linking Form Elements
For React 18+, use useId() instead:
import { useId } from 'react'
function FormField({ label }) {
const id = useId() // ✅ React's built-in solution
return (
<>
<label htmlFor={id}>{label}</label>
<input id={id} />
</>
)
}For React <18, Nano ID works:
import { nanoid } from 'nanoid'
import { useMemo } from 'react'
function FormField({ label }) {
const id = useMemo(() => nanoid(), []) // ✅ Generate once
return (
<>
<label htmlFor={id}>{label}</label>
<input id={id} />
</>
)
}