# React key warning: why it appears and when the index is wrong

React asks for a stable key on every list item. The index works only when the list is never reordered, filtered or extended.

> Page: https://ui.eneawork.it/blog/react-key-warning-liste
> Markdown: https://ui.eneawork.it/blog/react-key-warning-liste.md

*2026-11-01*

Risposta breve: React ha bisogno di una key stabile per riconoscere un elemento tra due render. Usa l'id del record. L'indice va bene solo per una lista statica che non cambia ordine.

La domanda «Understanding unique keys for array children in React.js» vale 1096 voti su Stack Overflow (letto il 31 ottobre 2026 con la Stack Exchange API): fonte. Il catalogo EneUI ha misurato 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. Ogni comando qui sotto è eseguibile in locale: nessun passaggio richiede un account.

## Il messaggio esatto

Warning: Each child in a list should have a unique "key" prop. Check the render method of `OrderList`. See https://react.dev/link/warning-keys for more information.

## Perché una key e non un indice

React non usa la key per il DOM: la usa per decidere quale istanza di componente conservare. Con l'indice, la riga 2 resta la riga 2 anche quando il record cambia, e lo stato locale, testo digitato, checkbox, focus, resta agganciato alla posizione.

## Il meccanismo: la key decide quale istanza sopravvive

Il reconciler confronta i figli di un elemento per posizione e per key. Quando la key cambia, React non aggiorna l'istanza: la smonta e ne crea una nuova. Smontare significa perdere lo stato locale, rieseguire gli effetti e sostituire il nodo del DOM. Per questo una key instabile non è un dettaglio di stile: è la differenza tra aggiornare una riga e ricostruire l'intera lista a ogni render. L'avviso che hai visto compare solo in sviluppo; in produzione il difetto resta e non stampa nulla.

## Un passo diagnostico per le key duplicate

L'avviso di React copre la key mancante, non quella duplicata: due record con lo stesso id producono silenzio. Il controllo qui sotto costa una funzione e va tenuto in sviluppo, non nel bundle di produzione: fallisce al primo valore ambiguo e ti dice quale si ripete. Se lo lanci e non fallisce, il problema non è nel dataset ma nel livello che lo trasforma: un map che riscrive l'id, una concatenazione con un indice, una chiave composta da campi modificabili.

// solo in sviluppo: fallisce subito su una key duplicata function assertUniqueKeys(rows: T[], keyOf: (row: T) => string) { const seen = new Set(); for (const row of rows) { const key = keyOf(row); if (seen.has(key)) throw new Error(`key duplicata: ${key}`); seen.add(key); } return rows; }

## La correzione

type Order = { id: string; total: number }; export function OrderList({ orders }: { orders: Order[] }) { return ( {orders.map((order) => ( {order.total} € ))} ); }

Se il record non ha un id, generane uno stabile alla creazione, non nel render. crypto.randomUUID() dentro il componente produce una key nuova a ogni render e React ricrea tutto: è peggio dell'indice.

## Frammenti e componenti

import { Fragment } from "react"; {rows.map((row) => ( {row.label} {row.value} ))}

La sintassi abbreviata <>...</> non accetta attributi: serve la forma esplicita. Lo stesso vale per un componente che restituisce più elementi.

## Quando la correzione non funziona

Se l'avviso resta, la key manca su un livello intermedio: un wrapper dentro il map che restituisce un array senza key. Se invece vedi comportamenti strani senza avvisi, cerca key duplicate: due record con lo stesso id non producono errore, ma React riusa la stessa istanza per entrambi.

## Quando la correzione comune peggiora le cose

La correzione istintiva sostituisce l'indice con qualcosa di unico generato al render: key={crypto.randomUUID()} oppure key={JSON.stringify(row)}. La prima cambia a ogni render e rimonta ogni riga, quindi il testo digitato sparisce, il focus si perde e le transizioni ripartono. La seconda sembra stabile ma dipende dall'intero contenuto: ogni carattere scritto in una riga editabile ne cambia la forma e rimonta la riga proprio mentre l'utente scrive. In entrambi i casi l'avviso sparisce e il comportamento peggiora. Una key deve essere stabile tra i render e unica tra i fratelli, e solo l'id del record soddisfa entrambe le condizioni.

## Un limite con un nome: id non univoci

Se il dataset contiene due record con lo stesso id, nessuna key li separa. Succede con i dati aggregati: due righe che arrivano dallo stesso ordine, un elenco che unisce i risultati di due ricerche, un join senza distinct. React non può inventare l'unicità che i dati non hanno, e il sintomo è una riga che eredita lo stato dell'altra. Il nome del limite è questo: la key eredita i difetti della sorgente. La correzione sta a monte, nell'identificatore con cui il record nasce, non nel markup.

## Come prevenirlo

Una regola ESLint chiude il caso della key mancante, non quello della key sbagliata. Per il secondo serve un test che riordina la lista e verifica che i valori digitati seguano il record: è l'unico modo per accorgersi di una key che compila, non avvisa e sbaglia.

## Dove continuare

Nel catalogo: data table con preview, componenti e blocchi. Le guide: checklist accessibilità e alternative a MUI; il confronto: Radix, Base UI e React Aria.

## FAQ

### Perché React non usa l'indice come default?

Perché l'indice cambia quando la lista cambia: React riuserebbe lo stato sbagliato su un'altra riga, producendo input e checkbox incoerenti.

### La key è visibile nel DOM?

No. La key è un'istruzione per il reconciler e non viene scritta come attributo HTML.

### Come do la key a un Fragment?

Con la forma esplicita Fragment, passando key come prop: la sintassi abbreviata non accetta attributi. La key non arriva al componente, quindi va letta fuori dalle props.

### Due elementi con la stessa key cosa causano?

React avvisa in sviluppo e può riusare lo stato nel posto sbagliato. Il sintomo tipico è un input che conserva il valore della riga precedente.

### Serve una key sulle liste statiche?

Sì, React la chiede comunque. Su una lista davvero statica l'indice è accettabile, ma una key semantica resta più chiara.
