We all have ways of remembering where we last put our apartment or car keys. After all, we all know the fear of losing them, don’t we?
Applications written in React also have keys. And they are as important as those to your apartment. Or even more sometimes - especially when a deadline is around the corner and your React code is bright red.
From this article, you'll learn about React's mysterious keys - both in theory and practice, what you need to know about indexes, and more. Last but not least, it will cover how to avoid the terrifying red color warning.
What is React? A definition
React is an open source JavaScript library, which is why you often come across names like Reactjs or React.js from different sources. In this article, both these names will be used, but please keep in mind that they are the same solution.
React is a Facebook product that had its initial release in 2013, and was set up by one of its developers. It is used mainly by front-end developers to create user interfaces or different reusable UI components. React.js is often chosen as a solution for handling the view layer for both web and mobile applications and the already-mentioned user interfaces for single-page applications. What is more interesting is the fact that React is an entirely free solution.
React.js regularly takes its place in the top three in the ranking of frameworks chosen by developers. In this survey, you can see that since 2016, React has been at least second on the sheet. What makes this framework so loved by developers?
Introduction to React keys
Warning: Each child in a list should have a unique “key” prop.
I firmly believe that each React developer, at least once, saw this horrific warning in their console.
If you see a message like this on your screen the reason is clear: you haven’t used the "key" prop.
When I saw this warning for the first time, after a short panic, I started wondering how to resolve the issue and noted down some problems:
🔑 What do React keys look like in practice?
🔑 Why does React need them?
🔑 Can I use indexes?
🔑 What does the red warning mean?
Let's follow up with those questions and try to figure this out together.
What do React keys look like in practice?
A "key" is a particular string attribute you need to include when creating lists of elements. But what does your React code look like without them?
Let's create a simple example (with randomly generated names) of when a warning will be displayed in the console.
import ReactDOM from 'react-dom';
const NamesList = ({ names }) => {
const listItems = names.map((name) => <li>{name}</li>);
return <ul>{listItems}</ul>;
};
const names = \['Edyta', 'Joanna', 'Piotr', 'Filip', 'Dawid', 'Łukasz'];
ReactDOM.render(<NamesList names={names} />, document.getElementById('root'));
As you can see, using the built-in Array.map function isn’t enough, and the React code won’t look like you expect.
Now to rewrite the code to add the key attribute.
import ReactDOM from 'react-dom';
const NamesList = ({ names }) => {
const listItems = names.map((name, index) => <li key={index}>{name}</li>);
return <ul>{listItems}</ul>;
};
const names = \['Edyta', 'Joanna', 'Piotr', 'Filip', 'Dawid', 'Łukasz'];
ReactDOM.render(<NamesList names={names} />, document.getElementById('root'));
The warning is now gone, React is seemingly cured and won't bother us again. We can move on.
But are you sure that everything is working correctly now? Let's find out if this small change was enough for React, and why it needs keys so much?
Why does React need keys?
In short, it is all about Identity. A proper unique and stable Identity for the component will help React handle editing, modifying, and removing lists.
It is ‘common’ knowledge among many that adding keys will reduce/avoid additional rendering. This is not technically accurate, but you definitely shouldn’t ignore that message - keys are needed for component stability.
React has two phases:
- Render phase—React must first create VDOM objects and fiber nodes to compare attribute keys. In other words, React VDOM measures the changes that need to be committed to DOM.
- Commit phase—in the commit phase, React commits the changes to DOM.
What else differs between these phases? You can call the render phase multiple times. When we’re talking about the commit phase, the situation is different. You can call it only once for each change.
If you are interested in how React updates the components, you can find more about Reconciliation here.
Let’s return to our example and questions. I have already answered a few of them, but the next ones are waiting in the queue.
Can I use indexes?
An index is used inside the map() to state the position of every element in an array. In our example, we use a readily available index, a second parameter of the map function.
Each array has its index, and each key will be unique across the list. Does this resolve our problems? Not exactly.
I prepared a graphic to show you how React will react (😉) to different input statements.
Fig. 1 React with different input statements
What happens when we change the list order?
Fig. 2 Changed list order in React
As you can see, a lot of things have happened!
Every single component receives a different key now. In the render phase, React will check that the component with key 0 was Edyta and it is now Łukasz. React will assume that this component has changed and will push it to the commit phase. The same will happen to `Joanna`, `Piotr`, `Filip` and `Dawid`. When the key changes, React thinks it is someone else!
Now let’s focus on our terrifying red warning.
What does the red warning mean?
Imagine a case in which each component from the list has its own state. I will rewrite the application to mark the person as ready by clicking on a checkbox.
In addition, to make my statement valid, I will also allow for shuffling the list.
import ReactDOM from 'react-dom';
import { useState } from 'react';
const NameReady = ({ name }) => {
const \[ready, setReady] = useState(false);
return (
<li>
{name}
<input type='checkbox' checked={ready} onChange={() => setReady((prevReady) => !prevReady)} />
</li>
);
};
const NamesList = () => {
const \[names, setNames] = useState(\['Łukasz', 'Edyta', 'Joanna', 'Piotr', 'Filip', 'Dawid']);
return (
<div>
<button onClick={() => setNames((n) => \[...n.sort(() => 0.5 - Math.random())])}>Shuffle</button>
<ul>
{names.map((name, index) => (
<NameReady key={index} name={name} />
))}
</ul>
</div>
);
};
ReactDOM.render(<NamesList />, document.getElementById('root'));
So what is happening now? We allow the components to have their state: readiness.
Let's mark Łukasz and Joanna ready for action!
Fig. 3 React components with statements
Everything is working correctly for now. But what will happen if we shuffle the list a bit? Let's click the shuffle button to find out.
Fig. 4 Shuffled React components
Total disaster. Our generated personas who were ready are now mixed up and definitely unready. For React.js, those components changed their Identity, but they didn't create a new one. They took each other's Identity.
The problem was using the index as a key, and I think you already see a solution. For the list above, we could simply use the name for key attributes.
React will know that Filip is Filip and Dawid is Dawid, etc.
Each developer should find a proper solution for their cases.
I hope I’ll only have one Filip or one Dawid on my list in future...
Right now, you should know why I am concerned. This solution may not be perfect, but it is definitely enough.
Conclusion
React can only assume what you plan to do with your components, so you should give it a hint by using keys. They are a crucial element of any list.
Many will say that this is a limitation of React. I agree that using the key prop can be annoying and arduous sometimes. However, when compared to React’s simplicity, I can turn a blind eye to this and for me, it is an outstanding solution for controlling my components.
I also prepared a few examples of use cases where React played one of the leading roles:
- In this case, we created the UX & UI of a portal for monitoring data visualization.
- Here we used React as one of the technologies for building a web application for network monitoring in heterogeneous environments.
Or, if you want to build component-based applications more efficiently, you can consider integrating React with MobX. To check how to integrate MobX with React components, watch our video.