Tanvi Patel
Tanvi Patel

Reputation: 1327

error: Do not use Array index in keys

I am using index to generate key in a list. However, es-lint generates an error for the same. React doc also states that using the item index as a key should be used as last resort.

const list = children.map((child, index) =>
    <li key={index}> {child} </li>);

I considered using react-key-index. npm install react-key-index gives following error:

npm ERR! code E404

npm ERR! 404 Not Found: react-key-index@latest

Are there any suggestions on other packages that allow to generate unique key? Any suggestion on react key generator is appreciated!

Upvotes: 96

Views: 125134

Answers (8)

Ivan K.
Ivan K.

Reputation: 1124

Solution #1:

Use the Item Content as a key

The fastest walkaround

const children = ['Apple', 'Banana', 'Cherry'];

<div>
  {children.map((fruit) => (
    <li key={fruit}>{fruit}</li>
  ))}
</div>
Solution #2:

Concatenate Item Content with Index

const children = ['Apple', 'Banana', 'Cherry'];

<div>
  {children.map((fruit, index) => (
    <li key={`${fruit}-${index}`}>{fruit}</li>
  ))}
</div>

Upvotes: 2

rawr51919
rawr51919

Reputation: 19

I'd suggest using the reactjs-id library instead for React.js libraries, the react-key-index library hasn't been maintained for 7 years.

Unlike react-uuid, this should be able to have keys persist across page re-renders, however this hasn't been tested. I'd love to see input on this.

All you have to do on every array that requires random ids is:

import React from 'react'
import ReactId from 'reactjs-id'

const array = ['one', 'two', 'three']

export const LineItem = item => <li key={ReactId()}>{item}</li>

export const List = () => array.map(item => <LineItem item={item} />)

similarly to Haddad's solution.

Upvotes: -1

Rachel Nicolas
Rachel Nicolas

Reputation: 1165

The issue with using key={index} happens whenever the list is modified. React doesn't understand which item was added/removed/reordered since index is given on each render based on the order of the items in the array. Although, usually it's rendered fine, there are still situations when it fails.

Here is my example that I came across while building a list with input tags. One list is rendered based on index, another one based on id. The issue with the first list occurs every time you type anything in the input and then remove the item. On re-render React still shows as if that item is still there. This is a UI issue that is hard to spot and debug.

enter image description here

    class List extends React.Component {
      constructor() {
        super();
        this.state = {
          listForIndex: [{id: 1},{id: 2}],
          listForId: [{id: 1},{id: 2}]
        }
      }
      renderListByIndex = list => {
        return list.map((item, index) => {
          const { id } = item;
          return (
              <div key={index}>
                <input defaultValue={`Item ${id}`} />
                <button 
                  style={{margin: '5px'}} 
                  onClick={() => this.setState({ listForIndex: list.filter(i => i.id !== id) })}
                 >Remove</button>
              </div>
          )
        })
      }
      renderListById = list => {
        return list.map((item) => {
          const { id } = item;
          return (
              <div key={id}>
                <input defaultValue={`Item ${id}`} />
                <button 
                  style={{margin: '5px'}} 
                  onClick={() => this.setState({ listForId: list.filter(i => i.id !== id) })}
                 >Remove</button>
              </div>
          )
        })
      }
      render() {
        const { listForIndex, listForId } = this.state;
        return (
          <div className='flex-col'>
            <div>
              <strong>key is index</strong>
              {this.renderListByIndex(listForIndex)}
            </div>
            <div>
              <strong>key is id</strong>
              {this.renderListById(listForId)}
            </div>
          </div>
        )
      }
    }

    ReactDOM.render(
      <List />,
      document.getElementById('root')
    );
.flex-col {
  display: flex;
  flex-direction: row;
}

.flex-col > div {
  flex-basis: 50%;
  margin: .5em;
  padding: .5em;
  border: 1px solid #ccc;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <div id="root">
        <!-- This element's contents will be replaced with your component. -->
    </div>

Upvotes: 72

Toufiq  Choudhari
Toufiq Choudhari

Reputation: 1

In map method ,react render our array element with respect to key. so key plays a vital role. if we use index as key then in this case , if we re-order our components then , we will get problem because react render our array element with respect to key.

For more details go through this video https://www.youtube.com/watch?v=Deu8GE3Xv50&list=PLBHcDEyoOGlQ4o_Nx6FCXmjYlOAF2am6V&index=4&t=363s

Upvotes: -1

Darshan Sachaniya
Darshan Sachaniya

Reputation: 515

Of course, in React, you are required to pass in a unique key value for all elements of an array. Else, you will see this warning in console.

Warning: Each child in an array or iterator should have a unique “key” prop.

So, as a lazy developer, you would simply pass in the loop’s index value as the key value of the child element.

Reordering a list, or adding and removing items from a list can cause issues with the component state, when indexes are used as keys. If the key is an index, reordering an item changes it. Hence, the component state can get mixed up and may use the old key for a different component instance.

What are some exceptions where it is safe to use index as key?

  • If your list is static and will not change.
  • The list will never be re-ordered.
  • The list will not be filtered (adding/removing item from the list).
  • There are no ids for the items in the list.

Key should be unique but only among its siblings.

Upvotes: 13

Daniel Danielecki
Daniel Danielecki

Reputation: 10590

Do not use array indexes as keys, this is an anti-pattern that is pointed out by the React team in their docs.

It's a problem for performance and for state management. The first case applies when you would append something to the top of a list. Consider an example:

<ul>
  <li>Element1</li>
  <li>Element2</li>
  <li>Element3</li>
</ul>

Now, let say you want to add new elements to the top/bottom of the list, then reorder or sort the list (or even worst - add something in the middle). All the index-based key strategy will collapse. The index will be different over a time, which is not the case if for each of these elements there would be a unique id.

CodePens:

Play with it and you'll see that at some point the index-based key strategy is getting lost.

Upvotes: 5

HADDAD
HADDAD

Reputation: 69

use the following lib "react-uuid" : https://www.npmjs.com/package/react-uuid.

react-uuid basically create random ids when you call it each time.

import React from 'react'
import uuid from 'react-uuid'

const array = ['one', 'two', 'three']

export const LineItem = item => <li key={uuid()}>{item}</li>

export const List = () => array.map(item => <LineItem item={item} />)

and this should solve the issue.

Upvotes: -6

palsrealm
palsrealm

Reputation: 5243

When you use index of an array as a key, React will optimize and not render as expected. What happens in such a scenario can be explained with an example.

Suppose the parent component gets an array of 10 items and renders 10 components based on the array. Suppose the 5th item is then removed from the array. On the next render the parent will receive an array of 9 items and so React will render 9 components. This will show up as the 10th component getting removed, instead of the 5th, because React has no way of differentiating between the items based on index.

Therefore always use a unique identifier as a key for components that are rendered from an array of items.

You can generate your own unique key by using any of the field of the child object that is unique as a key. Normal, any id field of the child object can be used if available.

Edit : You will only be able to see the behavior mentioned above happen if the components create and manage their own state, e.g. in uncontrolled textboxes, timers etc. E.g. React error when removing input component

Upvotes: 107

Related Questions