After you’ve used React for only a short time, you’re likely to come across one of these warnings. Even experienced developers come across this error – usually due to an oversight in their code. Newbies to React encounter this error more often as they’re getting to grips with the framework.
We demystify this error here today and explain the cause and how to fix it.
What is a prop?
Props are simply arguments (or parameters) that are passed into React components. Thinking of languages like C++, the parameters that you pass to the constructor function would in essence be its props.
As an example, if we had a component called ‘Cake’ we might pass in a prop (or parameter) called ‘cakeType’:
<Cake cakeType="Chocolate" />;
Here, the value of the cakeType prop for this instance of the Cake React component is “Chocolate”.
Each component in react receives all the props as a single object. For example, the constructor of the Cake component might look something like:
function Cake(props){
const cakeType = props.cakeType;
....
}
As you can see, we therefore access the props object like any other object using the standard dot (.) notation.
What’s the cause?
The problem here is, using our example above, if we tried to produce a list of cakes.
Take this code for example:
...
const CakeShop = ({ cakes }) => (
<ul>
{cakes.map(cakes => <li>{cake.cakeType}</li>)}
</ul>
);
...
Not a problem eh? Anyone familiar with HTML will already be visualling the output in their mind. Say we add ‘Apple’, ‘Vanilla’ and ‘Toffee’ to our existing ‘Chocolate’ cake and add them all into the cakes object list (or array) above. We’re expecting an output something like:
<ul>
<li>Chocolate</li>
<li>Apple</li>
<li>Vanilla</li>
<li>Toffee</li>
</ul>
Nothing wrong with that I hear you say! And you’d be right…. in HTML! React expects each item (or child) in a list to be given a unique identifier called a “key”. Hence running the CakeShop component will give us the following error:
Warning: Each child in a list should have a unique "key" prop.
Fortunately for us, the solution is quite simple.
Adding the key prop.
As well as the cake type, we need to give a unique identifier. This can be automatically generated or manually specified but it must be unique! In our case, as things stand, the cakeType is unique. We could use this as a key but updating our code above to:
...
const CakeShop = ({ cakes }) => (
<ul>
{cakes.map(cakes => <li key={cake.cakeType}>{cake.cakeType}</li>)}
</ul>
);
...
Our list will display no issue now. If you prefer to add your own ID, you can either automatically generate it or provide it as a prop when your instantiating your Cake component:
<Cake key="1" cakeType="Chocolate" />;
<Cake key="2" cakeType="Apple" />;
<Cake key="3" cakeType="Vanilla" />;
<Cake key="4" cakeType="Toffee" />;
And then updating the constructor:
function Cake(props){
const cakeKey = props.key;
const cakeType = props.cakeType;
....
}
We can now generate our list using the new cakeKey as the key prop for each list item:
...
const CakeShop = ({ cakes }) => (
<ul>
{cakes.map(cakes => <li key={cake.cakeKey}>{cake.cakeType}</li>)}
</ul>
);
...
You won’t notice any difference visually between our cakeKey and cakeType examples but if you inspect the elements using developer tools you will notice the different key. The essential rule is to ensure that every element you have in a list must have its own unique ID – whatever you choose.
But I HAVE specified my key prop!
So, you’re still exasperated because you haven’t forgotten your key prop (common error #1) but are you setting it dynamically? This is where common error #2 creeps in. The value of the prop is undefined (initial/empty).
Using our example above, let’s say we instantiate our components the first way, with out using the key prop:
<Cake cakeType="Chocolate" />;
<Cake cakeType="Apple" />;
<Cake cakeType="Vanilla" />;
<Cake cakeType="Toffee" />;
Now, don’t forget, we’ve still already updated our mapping function to specify the key for each list item:
...
const CakeShop = ({ cakes }) => (
<ul>
{cakes.map(cakes => <li key={cake.cakeKey}>{cake.cakeType}</li>)}
</ul>
);
...
So what gives?
Well, let’s run through the output in our mind (as our application is going to fall over!).
<ul>
<li key="">Chocolate</li>
<li key="">Apple</li>
<li key="">Vanilla</li>
<li key="">Toffee</li>
</ul>
Spotted the problem? We have specified a key in our mapping function but we haven’t ensured that it’s unique! The keys are all the same blank value. If your list has one item, you’ll get away with it but you wouldn’t be routinely creating one-item lists I’m betting!
This error commonly occurs when you are using a dynamic variable as an ID (such as an auto-generating key) and there’s some data missing or you’ve run out of numbers in your number range. Debugging the ID assignment in the constructor of your React component should help you understand if you’re facing the issue.
The Golden Rules
- Always specify a key prop!
- Always ensure that your key prop is unique!
Happy coding. Let us know your comments below!