Search code examples
javascripthtmlreactjsreactive-programming

I am getting a unique key prop warning when i have a unique key


I am new to React but I know main concept of unique key. However, I am getting a warning.

Below I have an item component:

class Item extends Component {
    state = {}

    render() { 
        return ( 
            <React.Fragment>
                {this.props.item.todo}
            </React.Fragment>
        );
    }
}

And below is my items component and where i have unique keys:

render() { 
    const { items } = this.props;
    return ( 
        items.map(item=>
            <React.Fragment>
                <Item key={item.todo} item={item} />
            </React.Fragment>
        )    
    );
}

With all of this I am getting warning!


Solution

  • As others have said you need to set the key on the top element, in your case being Fragment. But I would change the key value. I don't know what kind of data you have in your item.todo but just setting the key to the value of item.todo could be problematic. I will explain.

    A key should be unique only among its siblings

    The react.org document on lists and keys sums this up perfectly, so I won't explain in another way. It says this below.

    Keys used within arrays should be unique among their siblings. However, they don’t need to be globally unique. We can use the same keys when we produce two different arrays:

    (Note: it does not need to be meaningful data).

    A key should be stable

    This means that between renders the key should not change, so don't use Math.random() which some people think would be good to use.

    Why is the above important?

    In your data, if two items.todo are the same value then it would break the above. Your key would not be unique. Which could cause performance issues from unnecessary re-renders.

    I would recommend using a key with the value of the items.todo and the index of the map. This way if you do have the same value for items.todo adding an index would make the key unique. With this in mind I would write your snippet.

    render() { 
      const { items } = this.props;
    
      return ( 
        items.map((item, index) => (
          <React.Fragment key={item.todo + index}>
            <Item item={item} />
          </React.Fragment>
        ))
      );
    }
    

    Here is link to the react.org documentation on list and keys and is a link to the react.org documentation regarding fragments. Both provide examples and useful information. They are a good read and I would highly recommend.

    Also something I noticed is that you're using React.Fragment but then you declare your class with just Component. Your could do what I'm assuming you've done for Component and destructure the Fragement. Something like below:

    import React, { Component, Fragment } from 'react';
    

    So you're snippet is a bit more clean, like below:

    items.map((item, index) => (
      <Fragment key={item.todo + index}>
        <Item item={item} />
      <Fragment>
    ))