React generates this warning when you render a list of elements without a key for each element. When you render a list of elements or components, React expects a unique key for each element, mainly for performance improvements. Refer to the Reconciliation section of the official React docs.
React needs a unique key to identify each list item uniquely. That is important when you render a long list and later perform changes to that list. Keys play an important role in below operations. The key should be unique and remain the same during each re-render. Random numbers should never be assigned as keys.
React identifies each list item by its key.
When React re-renders the array, it uses the key to identify each item. Therefore, React leaves existing items as they were, and only inserts the new item. So, no re-rendering happens to existing items.
Without keys in the list items, React cannot identify which element got inserted into the array. React only sees the mismatch between the state array and rendered array. To match them, React adds an extra item into the dom array and re-renders the entire array to reflect the new addition.
Without keys in the list items, React doesn't know which item got deleted. Therefore, React re-renders the entire list to reflect the state array in which the item got deleted.
Just like when inserting and deleting, if React can identify the exact item that got edited, React can re-render only that edited item, leaving the rest of the dom array untouched. Keys help uniquely identify items in the array.
Sorting is re-arranging the same set of items in a different order. Without a key, React re-renders the entire list when sorting occurs. In order for sorting to work efficiently, you should have a unique constant key attached to each item in the list. Randomly generated numbers or array indexes will not work.
If you don't use a key, React will use the array indexes as the keys. That is ok, as long as you don't mutate or sort the list. Since the first list item key will always be 0 and the last item key will always be the length of the array, there will be no re-renders as long as the state array remains unchanged. But if you mutate or sort the state array, the key association will change, causing a re-render.
Always avoid assigning random numbers as keys. No matter what, React will always re-render the list. That is because keys change every time the component re-renders. Example React code to demonstrate insert, delete and sort
Below is a sample React code to demonstrate inserting, deleting, and sorting a list with and without keys. Feel free to remove the key from
import { useState } from 'react';
import Tr from './components/Contact';
export const App = () => {
const [arr, setArr] = useState([
{id: 1, name: "A1", score: "90"},
{id: 2, name: "A2", score: "91"},
{id: 3, name: "A3", score: "92"}
])
const style = {border: "1px solid black", "borderSpacing": "5px"}
const addRowTop = () => {
const l: number = arr.length+1
const newArr = [{id: l, name: `A${l}`, score: 92+l+""}]
setArr(newArr.concat(arr))
}
const addRowBottom = () => {
const l: number = arr.length+1
const newArr = [{id: l, name: `A${l}`, score: 92+l+""}]
setArr(arr.concat(newArr))
}
const deleteRow = (id: number) => {
const newArr = arr.filter((item) => item.id != id)
setArr(newArr)
}
const sortArray = () => {
const sortedArr = [...arr]
sortedArr.sort((a,b) => a.id - b.id)
setArr(sortedArr)
}
return(
<>
<table style={style}>
<tbody>
{arr.map((val, i) =>
<Tr row={val} onDelete={deleteRow} key={Math.random()}/>
)}
</tbody>
</table>
<br/>
<button onClick={addRowTop}>Add Top</button>
<button onClick={addRowBottom}>Add Bottom</button>
<button onClick={sortArray}>Sort Array</button>
</>
)
}
import { useEffect } from "react"
interface trow {row: {id: number, name: string, score: string}, onDelete: Function}
const style = {border: "1px solid black", "padding": "5px"}
const Tr = (tr: trow) => {
const {id, name, score} = tr.row
useEffect(() => {
console.log("Re-Rendered "+name)
}, []);
return (
<tr>
<td style={style}>{id}</td>
<td style={style}>{name}</td>
<td style={style}>{score}</td>
<td style={style}><button onClick={() => tr.onDelete(id)}>Delete</button></td>
</tr>
)
}
export default Tr