This error occurs when you have a list of elements that don’t have a key
prop defined. This prop tells React which element is which and helps it to understand when to re-render elements. Fix this by adding a key
prop to each element and setting it to a value that uniquely identifies the element.
This error occurred recently for me when working on our React routes tutorial. Let’s take a look at the situation that caused it.
The problem: missing key prop
Below is our <Messages>
component from our real-time chat app example:
import { useSubscription } from "urql";
import "./Messages.css";
const MESSAGES = `
subscription {
room {
messages {
sender {
name
}
text
}
}
}
`;
function Message({sender, text}) {
return (
<div className="message">
<div className="sender">{sender}:</div>
<div className="text">{text}</div>
</div>
);
}
export default function Messages() {
const [{data, fetching}] = useSubscription({query: MESSAGES}, (_, data) => data);
if (fetching) {
return (
<h1>Loading...</h1>
);
} else {
return (
<div>
<div id="messages">
<div>
{data?.room.messages.map((message) => (
<Message
sender={message.sender.name}
text={message.text}
className="message"
/>
))}
</div>
</div>
</div>
);
}
}
JavaScriptWhat we’re doing here is fetching some messages from the backend, then displaying them to the user. The problem is occurring in our return
statement, where we actually return the components we want to render. Pay special attention to the data?.room.messages.map
call here:
<div>
<div id="messages">
<div>
{data?.room.messages.map((message) => (
<Message
sender={message.sender.name}
text={message.text}
className="message"
/>
))}
</div>
</div>
</div>
JavaScriptThis seems fine, and like it should render the messages correctly – and it does. But if you have your developer console open, you’ll see the following warning:
Let’s see how we can fix this.
Solution 1 (recommended): Use a unique ID from the database
The recommended way to prevent the “unique key prop” warning in React is to actually have a unique key value to assign to props in a list:
<div>
<div id="messages">
<div>
{data?.room.messages.map((message) => (
<Message
key={message.Id}
sender={message.sender.name}
text={message.text}
className="message"
/>
))}
</div>
</div>
</div>
JavaScriptIf your prop corresponds to a row in a database, it would be trivial to just set the key to that row’s ID, which is guaranteed to uniquely identify it.
Ours doesn’t, however, so we’ll need to take a different approach.
Solution 2: Set the key prop to a UUID
If you’re not able to get a unique ID from the database, you can always generate one yourself, and UUIDs are a good way to do this.
React doesn’t have a built-in way to generate UUIDs, but you can easily install the uuid
package via NPM with the following command:
npm install uuid
ShellScriptThen, in our component, we import UUID V4 function with the following line:
import { v4 } from "uuid";
JavaScriptAdding a unique key to our <Message>
props then is as easy as calling the v4()
function we imported:
<div>
<div id="messages">
<div>
{data?.room.messages.map((message) => (
<Message
key={v4()}
sender={message.sender.name}
text={message.text}
className="message"
/>
))}
</div>
</div>
</div>
JavaScriptYes, this does mean that the unique key
prop will change every render, but that doesn’t actually matter. React just needs to be able to uniquely identify items in a list for that render.
Solution 3: Set the key prop to the index
This solution is the simplest of all. Just use the second parameter of the map
method (the current index) and assign the key
prop the value:
<div>
<div id="messages">
<div>
{data?.room.messages.map((message, index) => (
<Message
key={index}
sender={message.sender.name}
text={message.text}
className="message"
/>
))}
</div>
</div>
</div>
JavaScriptDon’t use the index if the order of the elements in the list could change, stick with a database row ID or generated UUID instead.
Conclusion
In this article, we covered what causes the React error “Each child in a list should have a unique ‘key’ prop” and how to fix it. The issue is caused by React not being able to uniquely identify sibling elements in a generated list, which can cause problems with re-rendering. To fix it, simply assign a unique value to the key
prop of each element as you’re generating the list. Ideally, you’d use the database’s row ID for that element, if it corresponds to one. If you can’t do that, and you don’t plan on re-ordering the list, you can use the current index of the loop. Finally, if all else fails, you can install the uuid
package and use their v4
method to generate a UUID for each item.
John is a professional software engineer who has been solving problems with code for 15+ years. He has experience with full stack web development, container orchestration, mobile development, DevOps, Windows and Linux kernel development, cybersecurity, and reverse engineering. In his spare time, he’s researching the potential business applications of AI.