If you have used React for your project you must have noticed one thing. React has such a big problem with arrays. So, in this article, we will see why does React need a key prop.
Why does React need a key prop?
If you’ve used React for a while, you’ve probably run into this before:
index.js:1 Warning: Each child in a list should have a unique “key” prop.
Check the render method of `App`. See https://reactjs.org/link/warning-keys for more information.
at li
at App (http://localhost:3000/static/js/30.chunk.js:48:75)
Also, you probably know the solution as well. Here’s the rule:
Whenever you’re rendering an array of React elements, each one must have a unique key prop. So, here’s the simplest way to reproduce this problem:
const items = [
{id: ‘apple’, value: ‘apple’},
{id: ‘orange’, value: ‘orange’},
{id: ‘grape’, value: ‘grape’},
{id: ‘pear’, value: ‘pear’},
]
function App() {
return (
<ul>
{items.map((item) => (
<li>{item.value}</li>
))}
</ul>
)
}
But the solution is pretty simple:
– <li>{item.value}</li>
+ <li key={item.id}>{item.value}</li>
But why React doesn’t seem to have a problem if we were to write it like this:
function App() {
return (
<ul> <li>apple</li>
<li>orange</li>
<li>grape</li>
<li>pear</li>
</ul>
)
}
It’s only a problem if we try to pass the elements as an array. So, why does React have such a big problem with arrays anyway? Firstly, if you want to understand what problems can happen without the key prop, read Understanding React’s key prop. However, in this post, we just want to explain why React can’t just make things work without a key
prop.
Let’s pretend you’re React and we are a React developer building an application. So, we are writing a function component called App. However, you don’t get to see my implementation, all you get is the function from which you can pass arguments and receive a return value. So let’s say we give you that function and tell you to render that to the page. After that, you call App and you get the following React elements back (learn more about React elements):
const element = {
type: ‘ul’,
key: null,
props: {
children: [
{type: ‘li’, key: null, props: {children: ‘apple’}},
{type: ‘li’, key: null, props: {children: ‘orange’}},
{type: ‘li’, key: null, props: {children: ‘grape’}},
{type: ‘li’, key: null, props: {children: ‘pear’}},
],
},
}
But first, you’re going to warn right? Because the key is null for all of those children. But you know how to take these elements and render them to the page. In addition, you render the ul
and li
to the page. So, now my App calls a state updater function and so you know you need to re-render. Also, you call App again and this time you get some new React elements:
const element = {
type: ‘ul’,
key: null,
props: {
children: [
{type: ‘li’, key: null, props: {children: ‘apple’}},
{type: ‘li’, key: null, props: {children: ‘orange’}},
{type: ‘li’, key: null, props: {children: ‘pear’}},
],
},
}
So, you do a quick and easy diff here:
– {type: ‘li’, key: null, props: {children: ‘grape’}}
Also, you need another state update, so you get the next set of React elements:
const element = {
type: ‘ul’,
key: null,
props: {
children: [
{type: ‘li’, key: null, props: {children: ‘apple’}},
{type: ‘li’, key: null, props: {children: ‘pear’}},
],
},
}
Now do another diff:
– {type: ‘li’, key: null, props: {children: ‘apple’}},
– {type: ‘li’, key: null, props: {children: ‘orange’}},
+ {type: ‘li’, key: null, props: {children: ‘apple’}},
However, interestingly this means that rather than just unmounting the grape
li
on that first state update, you actually unmounted
pear and updated
grape
to say pear
. Unmounting and mounting components have implications on the state and side-effects of a component.
And that also means with this last state update, you unmounted
pear again and updated
apple to be
apple
and
orange got updated to say
pear
. This is definitely not the most optimal, but what are you gonna do? You have no idea what is with the element change!
Now comes the ‘key’ prop
What if you have some way to track the React elements from one render to the next so your diff could be more informative. That way you’d know intent much better.
const element = {
type: ‘ul’,
key: null,
props: {
children: [
{type: ‘li’, key: ‘apple’, props: {children: ‘apple’}},
{type: ‘li’, key: ‘orange’, props: {children: ‘orange’}},
{type: ‘li’, key: ‘pear’, props: {children: ‘pear’}},
],
},
}
So, now here comes the update for you:
const element = {
type: ‘ul’,
key: null,
props: {
children: [
{type: ‘li’, key: ‘apple’, props: {children: ‘apple’}},
{type: ‘li’, key: ‘pear’, props: {children: ‘pear’}},
],
},
}
So, now you know exactly what to do. In addition, you can now do a much more granular diff. Firstly, you notice that the element with the key
of 'orange'
is gone. So you know you can remove that from the page. Also, the element with the key
of 'apple'
has new children.
So you can simply update it and move on without worrying about whether you’re doing the right thing.
Conclusion
So, in this article, we discussed why does React needs a key prop. Feel free to comment with your suggestions and feedback. At BOSC Tech Labs, we have a team of highly experienced React JS developers who can assist you in developing your customized web app. So contact us to hire experienced React JS developers.