Right Usage of Keys in React
Guide on how to choose proper key to improve your app's performance
Table of contents
Usage
Keys are used by React internal algorithm (Reconciliation or React’s “diffing” algorithm) to determine what changes it needs to apply to UI in while updating UI.
Before React, Browsers were repainting the entire UI for every change, even if it's small subset of the screen which needs a repaint.
React have very efficient algorithm where it creates a virtual dom tree of a complete app containing components and its dom element. When there is a change required in UI as an effect of user interaction (for eg - toggle between dark and light theme) or some change triggered by backend (notification received) You can read more about it here
Coming back to the importance/usage of keys, React depend on you (as a developer) to use permanent and unique property as Keys so that it can optimize performace or repaint screen in most efficent manner.
Side Effect of incorrent key usage
When a key of a component is updated (changed from a
to b
), React discards/flushes the current component and creates a new instance of the component.
Here, component lifecycle methods are invoked such as componentDidMount, ComponentWillMount (for newly mounted instance) and componentUnMount (for old instance)
For eg - Network call in componentDidMount will be invoked again which may or maynot be desired.
Do's
- Use unique and permanent properties as keys.
- Keys should be unique within its siblings. No need to make it unique across the complete app. for eg -
const Item = (item) => {
return (
<li>{item.value}</li>
)
}
const Home = () => {
const itemList = [{id: '#1',value: 'hello world'}, {id: '#2',value: 'second line'}, {id: '#3',value: 'third line'}]
return (
<div>
<ul>
{itemList.map((item) => {
return <Item key={item.id} item={item}/>
})}
</ul>
// incorrect or no need for prefixing random text
<ul>
{itemList.map((item) => {
return <Item key={'secondarray'-${item.id}} item={item}/>
})}
</ul>
</div>
)
}
Don'ts
- Do not generate ids in runtime as keys. On every render cycle(runtime) new ids will be generate. Which means, unnecessary component mount and unmounting. for eg -
import { nanoid } from 'nanoid'
const Home = () => {
const itemList = ['hello world', 'second line', 'third line']
return (
<ul>
{itemList.map((item) => {
return <li key={nanoid()}>{item}</li>
})}
</ul>
)
}
- No need to pass keys down the component tree
// incorrect usage
const Item = (item) => {
return (
<li key={item.id}>{item.value}</li>
)
}
// correct usage
const Item = (item) => {
return (
<li>{item.value}</li>
)
}
const Home = () => {
const itemList = [{id: '#1',value: 'hello world'}, {id: '#2',value: 'second line'}, {id: '#3',value: 'third line'}]
return (
<ul>
{itemList.map((item) => {
return <Item key={item.id} item={item}/>
})}
</ul>
)
}
- Using Index from Array should be last resort and internally React uses indes as keys if not provided.