What you should know about React Key Prop
Tags: react, javascript, frontend
Published: 2022-12-26 23:52:02

In this post we'll understand what is React key prop used for, and how should we use it

React has it's virtual DOM, it applies changes on this **virtual DOM**, then calculates the difference between this **virtual DOM** and the **real DOM** that appears on browser


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csqq7sernr6qlxkls9wz.png)


As we can see React has the virtual DOM in a tree, When a state changes it determines the affected nodes, then apply changes to them, then it applies differences to the real DOM

In case of rendering lists React needs to identify exactly each element, Why? Imagine having a simple component like this

```javascript
const TodoList = () => {
  const [todoList, setTodoList] = useState([
    {id: 1, text: 'Playing football'},
    {id: 2, text: 'Studying'},
    {id: 3, text: 'Sleeping'}
  ]);
  return (
    <ul>
      {todoList.map((item) => (
        <li>{item.text}</li>
      ))}
    </ul>
  );
};

export default TodoList;
```

In virtual DOM this component will be presented like this
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rhx86fmmruy07fy2sewj.png)


As we can see, the li elements depends on the **todoList state**, And every time we set this state (Adding, modifying or removing items from the todoList) we'll be setting a **new array** to it with a new reference, So React will take the new array and create new **_li_** elements using the new array ... Here exactly React needs something that identify the old elements that were already rendered using the previous state not to recreate them, That's why they created the **Key Prop**

To have a valid Key prop, it should

1. Have a constant value that doesn't change with each render, so we shouldn't do something like this

```javascript
return (
    <ul>
      {todoList.map((item) => (
        <li key={Math.random()}>{item.text}</li>
      ))}
    </ul>
);
```
Math.random() will be called with every render and generate a new random value, So every render React will identify all elements as new elements and create them from scratch which leads to a weak performance

Instead, We should have a key that doesn't change with new renders, Like id coming from DB or even an id generated with Math.random() but created in the initialization only

```javascript
const TodoList = () => {
  const [todoList, setTodoList] = useState([
    {id: Math.random(), text: 'Playing football'},
    {id: Math.random(), text: 'Studying'},
    {id: Math.random(), text: 'Sleeping'}
  ]);
  return (
    <ul>
      {todoList.map((item) => (
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
};
```

2. It should be unique per siblings, So each sibling should have a different key than it's siblings

**Why shouldn't we use index as a key?
**

```javascript
  return (
    <ul>
      {todoList.map((item, index) => (
        <li key={index}>{item.text}</li>
      ))}
    </ul>
  );
```
React uses index as a default key if We don't assign a key, But the risk here is that if We add an element to the beginning of the array it'll have key=0 which was the key of the current second element of the array, Same thing will happen if we add or remove elements from the array.
This will be very clear if we use inputs as an example

```javascript
   {todoList.map((item, index) => (
     <li key={index}>
        <p>{item.text}</p>
        <input />
     </li>
   ))}
```

The first item here has a **key=0**, If we write anything in it's input, then add a new item to the beginning of our todo list, The new added item will have **key=0**, and the old item which we've written in it's input will have **key=1**, Now on the screen we'll see what We've written in the second item appearing in the first item cause React identifies the element only by it's key ... That's why **index is not preferred to be used as a key**

There's another one good hack about keys, For React a new key means a new element with new states ... And sometimes we need to reset component states, What we usually do in this case we create a **useEffect** and listen to a variable then reset states when this variable changes, Like this example

```javascript
  const [posts, setPosts] = useState([]);
  const [comments, setComments] = useState([]);
  const [likes, setLikes] = useState([]);

  useEffect(() => {
    setPosts([]);
    setComments([]);
    setLikes([]);
  }, [useId]);
```

Instead of doing this, We can simply pass userId as a key to this component and when userId changes, it'll have a **new key** and a **new states
**
```javascript
<UserProfile key={userId} />
```

## Conclusion

1. Key is important for React not to recreate list items
2. Key must be unique for each sibling
3. Key must have a constant value that doesn't change while rendering
4. Index isn't preferred to be used as a key
5. Key can be used to reset component states

Thank u!