4

I'm getting the common error: Warning: Each child in an array or iterator should have a unique "key" prop.

In general, finding the offending code is easy, but this time it is not. What I would like to know is what are the key values for the items being displayed.

(Q) Is there a way for me to see what each key property's value in the DOM that is rendered?

When I inspect the HTML generated lists that react has rendered, I don't see the key property on the DOM elements (nor would I expect to see it), but that is what I'm asking to see. Is there a flag I can set to ask React to add that key property value to the DOM so I can see it?

This would let me see where I'm missing a key, or have two keys with the same value (this is the problem I think I have). See Find Duplicated Key in a complicated React component

At this point, I'm doing the methodical approach of rendering one item at a time to isolate which item has the problem so I can zero in and find the offending code.

Searching for solutions

When searching for solutions there are several good write ups on how this works and why keys are needed, and they are shown below.

Community
  • 1
  • 1
PatS
  • 8,833
  • 12
  • 57
  • 100
  • 1
    Have you tried using [React DevTool](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)? It will let you see props for each components. – Min Lee Dec 07 '19 at 01:03
  • 2
    Are you setting a key in the first place? It sounds like you are iterating through an array and rendering a react component for each value. Take a look at the [Lists and Keys](https://reactjs.org/docs/lists-and-keys.html#keys) section of the official docs. – woat Dec 07 '19 at 01:09
  • Can you post your code? – ravibagul91 Dec 07 '19 at 01:14
  • 2
    Best solution is to rely on a unique value. If you're not able to provide that based on any specific property of your data structure then use index of your loop. If you can't use index as you need to move the items in the list then you can generate a unique ID from your data structure. Best would be JSON.stringify() ;) – Amin Paks Dec 07 '19 at 01:17
  • 1
    @Min Lee, I'm not using React DevTool, and will look into that. Does that show the key values? – PatS Dec 07 '19 at 01:24
  • @ravibagul91, Sorry I can't post the code. I don't have the problem isolated to a small set of files. – PatS Dec 07 '19 at 01:27
  • @woat, I can't know for sure that I'm setting a key either. I'm instrumenting the code now, with console.log() statements of the keys that I'm using to see if any are null, or not unique. – PatS Dec 07 '19 at 01:28
  • 2
    @PatS Yes, the dev tool will allow you to see the tree structure of all your components alongside with keys, props, and states. You should be able to see it if you are setting a key properly (ex: ``) – Min Lee Dec 07 '19 at 01:40
  • 2
    @PatS, the error you posted will come in 2 scenarios. First, if you don't set key at all and second if you have repeating key. Be sure for any loop you are setting unique key. – ravibagul91 Dec 07 '19 at 01:41

1 Answers1

1

Here is some explanation why Key is important and how to provide it to an array of children in React:

There are three List component in the example below. If you open it in the Chrome DevTools and click on the "Randomize sort" you will realize that the children of the lists are changing (they blink) but in the second example some more of the li elements are changing, the reason is React is removing and re-creating the li tag.

The efficient examples are the first and third List component because React knows instead of removing these group of elements it can to re-order them which is way faster!

I would NOT recommend the third (JSON.stringify) example, better always rely on a unique property from the data structure to avoid extra work.

const items = Array(10).fill(null).map((_, idx) => ({ id: String(idx) + Math.floor(Math.random() * 9999), title: 'Item '+(idx+1) }));

function List({ children, items, keyProp, indexType }) {
  return (
    <div style={{ borderBottom: '1px solid black', padding: '1em' }}>
      <h2>{children}</h2>
      <ul>
        {items.map((data, idx) => {
          const key = indexType === 'dataStructure'
            ? data[keyProp]
            : indexType === 'jsonStringify'
              ? JSON.stringify(data)
              : idx;
          return (
            <li key={key}>{data.title}, key: {key}</li>
          )
        })}
      </ul>
    </div>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { items };
    this.handleRandomize = this.handleRandomize.bind(this);
  }
  handleRandomize() {
    this.setState({ items: items.slice().sort(() => Math.round(Math.random() * 2) - 1) });
  }
  render() {
    return (
      <div style={{ background: 'red', marginBottom: '2em' }}>
        <button onClick={this.handleRandomize}>Randomize sort</button>
        <List items={this.state.items} indexType='dataStructure' keyProp='id'>
          <p>List renderd with unique "id" from data structure</p>
        </List>
        <List items={this.state.items} indexType='arrayIndex'>
          <p>List rendered with index of the loop</p>
        </List>
        <List items={this.state.items} indexType='jsonStringify'>
          <p>List rendered with JSON.stringify()</p>
        </List>
      </div> 
    )
  }
}

ReactDOM.render(<App />, document.querySelector('#root'));
<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"></div>
Amin Paks
  • 276
  • 2
  • 15