Back to: ReactJS Tutorials
Understanding Keys in React:
In this article, I will discuss Understanding Keys in React with Examples. Please read our previous article discussing Using Stateful Lists in React. We successfully added the new expense to the existing array in the last article. Then we’re getting the key-related warning.
Everything is working fine, so why are we getting this key warning? React has a special concept when it comes to rendering lists of data. A concept exists to ensure that React can efficiently update and render such lists without performance losses or possible bugs. And we want to show you which problem we have with the current implementation.
What is the problem in our implementation?
If you have a look at your Developer Tools and go to the Elements tab, you can inspect your list,
The above-highlighted list of divs is our list. If we have a look at this list here, then you should watch the part on the right in Developer Tools,
Now, if we add a new item, ‘book, 60.45, 26-08-2023’,
As we added a new item, the last div in the list flashed. This last item flashed. And if our item flashes, it means the browser edited or added it. Now, it’s strange that the last item flashed because, actually, the new item was added as the first item, the topmost item in this list. To understand what’s going on, let us expand the div in the list,
So, we have expanded the first item that we just added here. Now let us add another item here (notice the expanded div),
Here, you can see the expanded block of div in which the h2 tag has ‘Book’ text; now, it has been changed to ‘Drone’.
So, what actually happens here when we add a new item? React renders a new item as the last item in this list of divs, updates all the items, and replaces their content such that it again matches the order of the items in my Array. And this is not great.
This is happening because, to React, all these items look similar, and it only shows that our Array changed and that it’s no longer. Hence, it renders an additional div and adds that at the end. Then, it simply walks through all the items and updates the content inside of every item to match the Array content again.
How is performance affected?
Therefore, the final result is correct here. But from a performance perspective, this is not great because all items are visited and updated, which can lead to bugs. If the expense items are state-full items and we manage some state inside of that, then, for example, our first item has a certain state; if we add a new item, the old first item will be overridden with the new first item. Hence, whatever changes we have made in the state of that item will be lost.
So, apart from potential performance issues, we may also face bugs. So, that is a problem. And the question is, why does React behave like this? The answer is that it has no other way. It simply checks the length of the Array and then looks at the number of items that were already rendered. The individual items look similar to React, so it can’t know where a new item should be added or anything like that. That’s why we’re getting that warning: we can tell react where a new item should be added.
The correct way to add a new item in our array:
By going to the place where we output our list of items (In Expenses.js).
We will add a special prop to the ExpenseItem in the map method. And that’s the key prop.
This is not a prop we use inside the expense item; instead, it’s a prop you can add to any component. No matter if it’s a custom component or if it’s a built-in HTML element, you can always add this.
And if you do add it, if you add the key to your component or HTML element, then you can help React to identify the individual items. For that, you need to set a unique value per list item; for example, it will be the expense in this case.id,
Because in our expenses Array, every item has a unique ID.
And if you wonder what you should do if you have no unique ID, then you can use the second argument which you get for the function that you passed to map
It is an automatically managed index, though it’s discouraged to use that since, with that, you can still run into bugs because the index for a given item is always the same and not directly attached to the content of the item.
For the ID, that’s different. Every item with a certain content has a clear, unique ID. In reality, it turns out that in most scenarios, you will have some unique ID because, typically, you will be rendering some data that will come from a database or anything like that. And there, you will work with unique IDs.
So finding some unique identifier is no problem, and you can use any primitive value, any number, or String as a unique identifier. So, here, we added the key prop that is pointing at expense.id. And once we do that, we no longer get that warning if we reload the page. If we inspect our list, inspect the first item of the list, and now if we add a new item again,
you will see that the h2 tag (Household Expense) didn’t flash; instead, another div flashed that is now added at the beginning of the list correctly. This div here, we mean, as it should be, because now React can identify all these items uniquely, and it’s therefore aware, not just how long the Array is but also of which items should be placed.
And it’s able to update this list more efficiently. So, long story short, you should always add such a key when mapping out lists of items. And we hope we have explained why the unique ID matters. You don’t need to know why. It’s enough if you add it. But we think it’s always important to understand what’s going on behind the scenes and why you’re doing something.
Expenses.js:
import React, { useState } from "react"; import ExpenseItem from "./ExpenseItem"; import "./Expenses.css"; import Card from "../UI/Card"; import ExpensesFilter from "./ExpensesFilter"; const Expenses = (props) => { const [filteredYear, setFilteredYear] = useState("2020"); const filterChangeHandler = (selectedYear) => { setFilteredYear(selectedYear); }; return ( <Card className="expenses"> <ExpensesFilter selected={filteredYear} onChangeFilter={filterChangeHandler} /> {props.items.map((expense, index) => ( <ExpenseItem key={expense.id} title={expense.title} amount={expense.amount} date={expense.date} /> ))} </Card> ); }; export default Expenses;
In the next article, I will discuss Outputting Conditional Content in React. In this article, I try to explain Understanding Keys in React with Examples. I hope you enjoy this Understanding Keys in React article.