React: Each child in a list should have a unique “key” prop

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>
        );
    }
}
JavaScript

What 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>
JavaScript

This 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>
JavaScript

If 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
ShellScript

Then, in our component, we import UUID V4 function with the following line:

import { v4 } from "uuid";
JavaScript

Adding 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>
JavaScript

Yes, 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>
JavaScript

Don’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.