Why React Needs Keys, Why It Matters
Tags: react, javascript, webdev, reason
Published: 2021-07-22 01:04:57

Everyone uses React library all know that whenever we use a map to render, we need to pass the key. Otherwise, React will "yell" at us like this.

![Screenshot 2021-07-16 at 10.34.55 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dnm767enscvyoph0fcq3.png)
 

Oh nooo 😱😱, we need to pass the key now and most of the time we will pass like this.

```js
list.map((l, idx) => {
    return (
        <div key={idx}>
            <span>{l}</span>
        </div>
    )
})
```
Problem solved ✅, no more warning 😎

But...😢😢
> Life is not a dream

Let jump into an example of why "*Like is not a dream*"

Our manager gives us a task to create a dynamic Form with multiple Input fields, the user is able to enter their information and allow us to add or delete Input.

![1626447469518_ae13dc59ab0162a034b12026de911944](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ur2mmc3xyjf070yeb3yo.gif)
 

So
- We already know how to render the map in React library ✅
- We already know how to use useState in React Hook with an array ✅
- We also know method push/splice on array ✅

Easy one lah 😎...

Without the beat, we set up our application

```js
export default function App() {
const [list, setList] = useState([]);

const handleDelete = (idx) => {
    list.splice(idx, 1);
    setList([...list]);
};

const handleAdd = () => {
    list.push(`Information ${list.length + 1}`);
    setList([...list]);
};

const handleChange = (idx, l) => {
    list[idx] = l;
    setList([...list]);
};

return (
    <div className="App">
        {list.map((l, idx) => {
            return (
                <div key={idx}>
                    {FancyComponent(l, handleChange, idx)}
                    <button onClick={() => handleDelete(idx)}>Delete</button>
                </div>
            );
        })}
        <button onClick={() => handleAdd()}>Add</button>
    </div>
    );
}

const FancyComponent = (l, handleChange, idx) => {
    const onChange = (e) => {
        e.preventDefault();
        handleChange(idx, e.currentTarget.value);
    };
   
    return <input defaultValue={l} onChange={(e) => onChange(e)} />;
}
```
Here is [Playground](https://codesandbox.io/s/nifty-lumiere-eepxh?file=/src/App.js)

Done!!! Feel super awesome 😁💪, it works like charm. We pass to our manager, our manager like 🤩😍

A few moment later, our manager comes back again. We thought he would asking for the beer to appreciate but he said he found a bug 😱😭. The deletion didn't work as expected 🥺

![1626448892647_303ec7c0d81218c121096366804e5f49](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywda9yon270nvqogq6fx.gif)
 

After he modified Information 3 to Information 323, deleted this input but the application deleted Information 4, Information 5

We like whattt 😱😱😱, how it could be possible!!!, it just only 50 lines of codes...

After put the console.log everywhere, googling, StackOverflow... We found the problem is **the index we passed before** is changed it makes ReactJS confused and render incorrect. 

And if we don't use idx anymore, use content instead. Problem solved! ✅

```js
<div className="App">
    {list.map((l, idx) => {
        return (
            <div key={l}>
                {FancyComponent(l, handleChange, idx)}
                <button onClick={() => handleDelete(idx)}>Delete</button>
            </div>
         );
     })}
    <button onClick={() => handleAdd()}>Add</button>
</div<
```
*PS: Still has an issue, waiting for anyone to figure it out. 😉*

So now you might wonder that it is React's bug?!. No, it is not React's bug. Let's deep dive into it

If you noticed that when we change the value of the input, it works perfectly but deleting didn't work well because "changing" and "moving" state it is very different. When "moving" React needs to know what key of component is which we passed as an index of the array and deleting is changing the index hence it makes ReactJS confused. So why React don't make the by itself.

Dan's explanation:

> React can’t make up a good key itself. Only *you* know how your data is structured and whether two circles in two renders are “the same” circle conceptually (even if all of its data changed) or not. Usually, you’d use an ID generated during data creation. Such as from a databaseReact can’t make up a good key itself. Only *you* know how your data is structured and whether two circles in two renders are “the same” circle conceptually (even if all of its data changed) or not. Usually, you’d use an ID generated during data creation. Such as from a database

It is 100% true, as an example, we go through above that it is a business requirement, as library React doesn't know what the key should be which only us, developers created those components.

**What happens if you pass a random key every time?**

> Well, you’re telling React that circles are *never* the same between renders. So if you have some state inside of them, it will be lost after every re-render. React will destroy and recreate every circle because you told it to.

We will lose the "beauty" of ReactJS, isn't it? I believe no one wants to re-render every single time unless you have special requirements.

You might wonder why this topic pops up now, the concept of Keys has been there for a long time. ReactJS core team has started to built-in deep support Animation so Keys will play a big role there and in the future.

**Bonus:**

- ReactJS Core will update documentation about keys for more details.
- You might have awake of ReactJS 18 Alpha out and you also can follow ReactJS 18 working group to follow what the changes and new APIs are.
- React 18: https://reactjs.org/blog/2021/06/08/the-plan-for-react-18.html
- React 18 Working Group: https://github.com/reactwg/react-18
Hope you enjoy the article 😊

> The article is inspired by Dan Abramov https://twitter.com/dan_abramov/status/1415279090446204929