Understanding unique keys for array children in React.js
Asked Answered
G

32

1055

I'm building a React component that accepts a JSON data source and creates a sortable table.
Each of the dynamic data rows has a unique key assigned to it but I'm still getting an error of:

Each child in an array should have a unique "key" prop.
Check the render method of TableComponent.

My TableComponent render method returns:

<table>
  <thead key="thead">
    <TableHeader columns={columnNames}/>
  </thead>
  <tbody key="tbody">
    { rows }
  </tbody>
</table>

The TableHeader component is a single row and also has a unique key assigned to it.

Each row in rows is built from a component with a unique key:

<TableRowItem key={item.id} data={item} columns={columnNames}/>

And the TableRowItem looks like this:

var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c) {
          return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

What is causing the unique key prop error?

Gleeson answered 4/2, 2015 at 19:6 Comment(4)
Your rows in JS array should have unique key property. It'll help ReactJS to find references to the appropriate DOM nodes and update only content inside mark-up but not re-render the whole table/row.Elated
Can you also share rows array or more preferably a jsfiddle? You dont need a key property on thead and tbody by the way.Balustrade
I added the row component to the original question @nilgun.Gleeson
Is it possible that some items do not have an id or have same id?Balustrade
L
937

You should add a key to each child as well as each element inside children.

This way React can handle the minimal DOM change.

In your code, each <TableRowItem key={item.id} data={item} columns={columnNames}/> is trying to render some children inside them without a key.

Check this example.

Try removing the key={i} from the <b></b> element inside the div's (and check the console).

In the sample, if we don't give a key to the <b> element and we want to update only the object.city, React needs to re-render the whole row vs just the element.

Here is the code:

const data = [
  { name: "Nuri", age: 28, city: "HO" },
  { name: "Talib", age: 82, city: "HN" },
  { name: "Jenny", age: 41, city: "IT" },
];

const ExampleComponent = React.createClass({
  render: function () {
    const infoData = this.props.info;
    return (
      <div>
        {infoData.map((object, i) => {
          return (
            <div className={"row"} key={i}>
              {[
                object.name,
                // remove the key
                <b className="fosfo" key={i}>
                  {" "}
                  {object.city}{" "}
                </b>,
                object.age,
              ]}
            </div>
          );
        })}
      </div>
    );
  },
});

React.render(<ExampleComponent info={data} />, document.body);

The answer posted by @Chris at the bottom goes into much more detail than this answer.

React documentation on the importance of keys in reconciliation: Keys

Lamelliform answered 4/2, 2015 at 19:16 Comment(21)
I added the component you're talking about to the original question.Gleeson
Should I be adding a key to the <tr> element?Gleeson
added extra info again nif it helps.Lamelliform
That doesn't fix it either. I added a key to the <tr> elements in TableRowItem and still get the error. I feel the error message would be different if the issue was within TableRowItem too. I originally did have the same error, but it referenced the TableRowItem component. I fixed that by adding the key as a property of the component. The error is now referring to the TableComponent.Gleeson
im tryng a fiddle with your code, is {this.props.data[c]} plain text?Lamelliform
Let us continue this discussion in chat.Lamelliform
I am running into the exact same error. Was this resolved after the chat? If so, can you please post an update to this question.Leeland
The answer works, Deke. Just make sure that key value for the prop is unique for each item and you're putting the key prop to the component which is closest to array boundaries. For example, in React Native, first I was trying to put key prop to <Text> component. However I had to put it to <View> component which is parent of <Text>. if Array == [ (View > Text), (View > Text)] you need to put it to View. Not Text.Lily
Why is is so hard for React to generate unique keys itself?Bunny
@DavorLucic, here is a discussion: github.com/facebook/react/issues/1342#issuecomment-39230939Haar
This is pretty much the official word on a note made in the issue chat linked to above: keys are about identity of a member of a set and auto-generation of keys for items emerging out of an arbitrary iterator probably has performance implications within the React library.Antre
should this key be unique only in that array or should be unique in the whole App?Ramification
@Ramification "The key only has to be unique among its siblings, not globally unique." as per : reactjs.org/docs/reconciliation.html#keysSlipcover
Linked to Codepen does not compile/run.Slipcover
Is there documentation explaining why not only the child nodes need a unique key, but also the children of those child nodes? I couldn't find anything about that specifically in the docs.Terrorstricken
This requires more emphasis: "Keys only make sense in the context of the surrounding array. For example, if you extract a ListItem component, you should keep the key on the <ListItem /> elements in the array rather than on the <li> element in the ListItem itself." -- reactjs.org/docs/…Newhall
Except that this example uses index as key which causes another React error: Do not use Array index in keysVariegation
to broad code example that it's difficult to see that you just need to add key={i} inside your mapping tag to fix the issue.Learnt
In general you should not use the array index as the key — it loses all benefit if you reorder the array — instead use a unique feature of the data inside the array.Icbm
This is a fundamental design error in React. it should not be up to the caller to generate such keys. If React needs a unique key to track the item in the DOM, fine...it should generate it. Apologies that this doesn't actually give a solution...it's getting uncomfortable living with React with so many elephants in the room.Contrabassoon
This is definitely not always the case. But in some scenarios, React seems to use a .map call internally for some code that we did not write with a .map. And sometimes the warning can appear and other times it won't, it is very inconsistent. In those cases, this solution does fix the problem...Grand
P
899

Be careful when iterating over arrays!!

It is a common misconception that using the index of the element in the array is an acceptable way of suppressing the error you are probably familiar with:

Each child in an array should have a unique "key" prop.

However, in many cases it is not! This is anti-pattern that can in some situations lead to unwanted behavior.


Understanding the key prop

React uses the key prop to understand the component-to-DOM Element relation, which is then used for the reconciliation process. It is therefore very important that the key always remains unique, otherwise there is a good chance React will mix up the elements and mutate the incorrect one. It is also important that these keys remain static throughout all re-renders in order to maintain best performance.

That being said, one does not always need to apply the above, provided it is known that the array is completely static. However, applying best practices is encouraged whenever possible.

A React developer said in this GitHub issue:

  • key is not really about performance, it's more about identity (which in turn leads to better performance). randomly assigned and changing values are not identity
  • We can't realistically provide keys [automatically] without knowing how your data is modeled. I would suggest maybe using some sort of hashing function if you don't have ids
  • We already have internal keys when we use arrays, but they are the index in the array. When you insert a new element, those keys are wrong.

In short, a key should be:

  • Unique - A key cannot be identical to that of a sibling component.
  • Static - A key should not ever change between renders.

Using the key prop

As per the explanation above, carefully study the following samples and try to implement, when possible, the recommended approach.


Bad (Potentially)

<tbody>
    {rows.map((row, i) => {
        return <ObjectRow key={i} />;
    })}
</tbody>

This is arguably the most common mistake seen when iterating over an array in React. This approach isn't technically "wrong", it's just... "dangerous" if you don't know what you are doing. If you are iterating through a static array then this is a perfectly valid approach (e.g. an array of links in your navigation menu). However, if you are adding, removing, reordering or filtering items, then you need to be careful. Take a look at this detailed explanation in the official documentation.

class MyApp extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: ["Item 1"]
    }
  }
  
  click = () => {
    this.setState({
      arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr),
    });
  }
  
  render() {
    return(
      <div>
        <button onClick={this.click}>Add</button>
        <ul>
          {this.state.arr.map(
            (item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
          )}
        </ul>
      </div>
    );
  }
}

const Item = (props) => {
  return (
    <li>
      <label>{props.children}</label>
      <input value={props.text} />
    </li>
  );
}

ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

In this snippet we are using a non-static array and we are not restricting ourselves to using it as a stack. This is an unsafe approach (you'll see why). Note how as we add items to the beginning of the array (basically unshift), the value for each <input> remains in place. Why? Because the key doesn't uniquely identify each item.

In other words, at first Item 1 has key={0}. When we add the second item, the top item becomes Item 2, followed by Item 1 as the second item. However, now Item 1 has key={1} and not key={0} anymore. Instead, Item 2 now has key={0}!!

As such, React thinks the <input> elements have not changed, because the Item with key 0 is always at the top!

So why is this approach only sometimes bad?

This approach is only risky if the array is somehow filtered, rearranged, or items are added/removed. If it is always static, then it's perfectly safe to use. For example, a navigation menu like ["Home", "Products", "Contact us"] can safely be iterated through with this method because you'll probably never add new links or rearrange them.

In short, here's when you can safely use the index as key:

  • The array is static and will never change.
  • The array is never filtered (display a subset of the array).
  • The array is never reordered.
  • The array is used as a stack or LIFO (last in, first out). In other words, adding can only be done at the end of the array (i.e push), and only the last item can ever be removed (i.e pop).

Had we instead, in the snippet above, pushed the added item to the end of the array, the order for each existing item would always be correct.


Very bad

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={Math.random()} />;
    })}
</tbody>

While this approach will probably guarantee uniqueness of the keys, it will always force react to re-render each item in the list, even when this is not required. This a very bad solution as it greatly impacts performance. Not to mention that one cannot exclude the possibility of a key collision in the event that Math.random() produces the same number twice.

Unstable keys (like those produced by Math.random()) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.


Very good

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={row.uniqueId} />;
    })}
</tbody>

This is arguably the best approach because it uses a property that is unique for each item in the dataset. For example, if rows contains data fetched from a database, one could use the table's Primary Key (which typically is an auto-incrementing number).

The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys


Good

componentWillMount() {
  let rows = this.props.rows.map(item => { 
    return {uid: SomeLibrary.generateUniqueID(), value: item};
  });
}

...

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={row.uid} />;
    })}
</tbody>

This is also a good approach. If your dataset does not contain any data that guarantees uniqueness (e.g. an array of arbitrary numbers), there is a chance of a key collision. In such cases, it is best to manually generate a unique identifier for each item in the dataset before iterating over it. Preferably when mounting the component or when the dataset is received (e.g. from props or from an async API call), in order to do this only once, and not each time the component re-renders. There are already a handful of libraries out there that can provide you such keys. Here is one example: react-key-index.

Pleasant answered 10/5, 2017 at 12:44 Comment(15)
In the official docs, they use toString() to convert to string instead of leaving as number. Is this important to remember?Gabriellia
@skube, no, you can use integers as key as well. Not sure why they are converting it.Pleasant
I guess you can use integers but should you? As per their docs they state "...best way to pick a key is to use a string that uniquely identifies..." (emphasis mine)Gabriellia
@skube, yes that is perfectly acceptable. As stated in the examples above, you can use the item's index of the iterated array (and that's an integer). Even the docs state: "As a last resort, you can pass item's index in the array as a key". What happens though is that the key always ends up being a String anyway.Pleasant
should this key be unique only in that array or should be unique in the whole App?Ramification
@farmcommand2, keys are applied to React Components, and need to be unique among siblings. This is stated above. In other words, unique in the arrayPleasant
All numbers can be silently coerced into a string by the library itself, and there's generally (barring very large or very small numbers) a 1:1 ratio between a value's numeric representation and it's string representation (i.e. 5's string representation will always be "5" and vice versa).Haswell
@Gabriellia The reason is likely there's some type coercion "under the hood" so they just made a blanket statement to stick with strings. That's just an educated guess.Keelboat
I'd like to reiterate the importance of "it is best to manually generate a unique identifier for each item in the dataset before iterating over it. Preferably when mounting the component or when the dataset is received" I keep seeing people write key={uuid()} inside of the render function. This is not correct and causes the element to rerender when it shouldn't. As @Pleasant said, it should be done only once.Kenlay
@Kenlay It might seem incorrect, but doing uuid() in most "uuid" libraries will generate a key that remains static throughout re-renders (through memoization or other means), thus making that approach perfectly valid. As mentioned in my answer, the react-key-index library is an example of such behavior.Pleasant
@Pleasant I've seen it cause a rerender every time in the codebase I'm working in. I also ran a test in codepen with the cuid package and it had the same undesirable behavior. My intent is to warn others from thinking that they can just use a uuid to solve the problem. Can you explain how most uuid libraries solve this problem? react-key-index requires additional data to be passed in so that it can memoize. I don't understand how a generic uuid lib could accomplish the same thing by calling it with no arguments.Kenlay
@Kenlay I might've been wrong about how one implements react-key-index (probably confused it for another library), however I do know that there are libs out there that work as I described above. Can't recall the lib names though.Pleasant
@Pleasant I would be fascinated to know how they work if they don't have access to any additional data.Kenlay
This requires more emphasis: "Keys only make sense in the context of the surrounding array. For example, if you extract a ListItem component, you should keep the key on the <ListItem /> elements in the array rather than on the <li> element in the ListItem itself." -- reactjs.org/docs/…Newhall
Also worth pointing out is that the issue demonstrated in the code snippet (array values not updating to the correct location because of improper keys) will only manifest itself if you do not store these values directly in your array. However, even if you do, if you have changing keys, you will still lose in performance as React will have to update all the array items' values as their keys have changed.Grand
R
66

This may or not help someone, but it might be a quick reference. This is also similar to all the answers presented above.

I have a lot of locations that generate list using the structure below:

return (
    {myList.map(item => (
       <>
          <div class="some class"> 
             {item.someProperty} 
              ....
          </div>
       </>
     )}
 )
         

After a little trial and error (and some frustrations), adding a key property to the outermost block resolved it. Also, note that the <> tag is now replaced with the <div> tag now.

return (
  
    {myList.map((item, index) => (
       <div key={index}>
          <div class="some class"> 
             {item.someProperty} 
              ....
          </div>
       </div>
     )}
 )

Of course, I've been naively using the iterating index (index) to populate the key value in the above example. Ideally, you'd use something which is unique to the list item.

Recognizee answered 11/2, 2020 at 20:36 Comment(9)
This was extremely helpful, thank you! I didn't even realize I had to put it in the outermost layerAxel
I was doing similar groupings, but with table rows. You cannot wrap a table row in a div. Instead, wrap it in a react Fragment with a key, as demonstrated here: https://mcmap.net/q/54248/-how-do-i-wrap-a-react-component-that-returns-multiple-table-rows-and-avoid-the-quot-lt-tr-gt-cannot-appear-as-a-child-of-lt-div-gt-quot-errorSosna
Thank you. This helped me. I was using <></> inside map() Removing that helped me.Juryrigged
<> is a short syntax for <React.Fragment>. So if you want to add a key you can do like this: <React.Fragment key={item.id}>Stephaniestephannie
I had the same issue using Material-UI where I was using a List (and elsewhere a Menu) and placing the child items of those components inside a Tooltip. Giving the Tooltip the "key" instead of the ListItem/MenuItem itself got rid of the warning.Dodder
This was my issue too. I missed the Fragment.Eolith
Ahh, well done, this was my issue as well. Thank you!Waynant
you saved me thank youuuuuu ive been trying so long to solve my issueAtor
Thank you, removing the empty tag (added for convenience) solved it.Orsola
S
16

Check: key = undef !!!

You got also the warn message:

Each child in a list should have a unique "key" prop.

if your code is complete right, but if on

<ObjectRow key={someValue} />

someValue is undefined!!! Please check this first. You can save hours.

Swear answered 12/4, 2019 at 14:1 Comment(0)
C
11

Here are the React docs that explain well using the Key property, the key should be defined at the parent component it should not be used inside the child component.React Docs

enter image description here

enter image description here

Cheviot answered 15/5, 2022 at 9:46 Comment(1)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewTass
S
8

You should use a unique value for each children key of tbody where

  • the value cannot not be identical (same) to its sibling
  • should not change between renders

For example, the key value can be database id or UUID (Universal Unique Identifier).

Here the keys are handling manually:

<tbody>
  {rows.map((row) => <ObjectRow key={row.uuid} />)}
</tbody>

You can also let React handle the keys using React.Children.toArray

<tbody>
  {React.Children.toArray(rows.map((row) => <ObjectRow />))}
</tbody>
Siderolite answered 14/6, 2021 at 17:2 Comment(0)
R
7

Just add the unique key to the your Components

data.map((marker)=>{
    return(
        <YourComponents 
            key={data.id}     // <----- unique key
        />
    );
})
Razee answered 27/5, 2018 at 11:16 Comment(1)
The key data.id can't possibly be unique among the YourComponents.Precondition
B
5

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

This is a warning as for array items which we are going to iterate over will need a unique resemblance.

React handles iterating component rendering as arrays.

Better way to resolve this is provide index on the array items you are going to iterate over.for example:

class UsersState extends Component
    {
        state = {
            users: [
                {name:"shashank", age:20},
                {name:"vardan", age:30},
                {name:"somya", age:40}
            ]
        }
    render()
        {
            return(
                    <div>
                        {
                            this.state.users.map((user, index)=>{
                                return <UserState key={index} age={user.age}>{user.name}</UserState>
                            })
                        }
                    </div>
                )
        }

index is React built-in props.

Bangup answered 28/4, 2018 at 3:47 Comment(3)
This approach is potentially dangerous if the items are rearranged somehow. But if they remain static then this is fine.Pleasant
@chris I completely agree with you because in this case index may be duplicated. Better to use dynamic values for key.Bangup
@chris I also agree with your comment. We should use dynamic values rather then index because there may be duplicates. To make it simple I did this. Btw thanks for your contribution (upvoted)Bangup
C
5

When you don’t have stable IDs for rendered items, you may use the item index as a key as a last resort:

const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
   <li key={index}>
      {todo.text}
   </li>
);

Please refer to List and Keys - React

Caril answered 12/2, 2021 at 10:42 Comment(0)
V
4

In ReactJS if you are rendering an array of elements you should have a unique key for each those elements. Normally those kinda situations are creating a list.

Example:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

In the above example, it creates a dynamic list using li tag, so since li tag does not have a unique key it shows an error.

After fixed:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li key={n}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

Alternative solution when use map when you don't have a unique key (this is not recommended by react eslint ):

function List() {
  const numbers = [0,1,2,3,4,4];
 
  return (
    <ul>{numbers.map((n,i) => <li key={i}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

Live example: https://codepen.io/spmsupun/pen/wvWdGwG

Virtues answered 27/10, 2020 at 12:2 Comment(0)
S
3

Best solution of define unique key in react: inside the map you initialized the name post then key define by key={post.id} or in my code you see i define the name item then i define key by key={item.id}:

<div className="container">
                {posts.map(item =>(

                    <div className="card border-primary mb-3" key={item.id}>
                        <div className="card-header">{item.name}</div>
                    <div className="card-body" >
                <h4 className="card-title">{item.username}</h4>
                <p className="card-text">{item.email}</p>
                    </div>
                  </div>
                ))}
            </div>
Spalla answered 17/1, 2020 at 11:46 Comment(1)
was looking for this same answer even I had a component like this and was frustatedOminous
D
3

If we have array object data . then we map to show the data . and pass the unique id (key = {product.id} ) because browser can select the unique data.

example : [
    {
        "id": "1",
        "name": "walton glass door",
        "suplier": "walton group",
        "price": "50000",
        "quantity": "25",
        "description":"Walton Refrigerator is the Best Refrigerator brand in bv 
         Bangladesh "
    },
    {
        
        "id": "2",
        "name": "walton glass door",
        "suplier": "walton group",
        "price": "40000",
        "quantity": "5",
        "description":"Walton Refrigerator is the Best Refrigerator brand in 
         Bangladesh "
    },
}

now we are mapping the data and pass the unique id:

{
    products.map(product => <product product={product} key={product.id} 
    </product>)
}
Deconsecrate answered 8/5, 2022 at 8:51 Comment(0)
P
2

I was running into this error message because of <></> being returned for some items in the array when instead null needs to be returned.

Ploughboy answered 24/3, 2020 at 2:50 Comment(0)
L
2

I had a unique key, just had to pass it as a prop like this:

<CompName key={msg._id} message={msg} />

This page was helpful:

https://reactjs.org/docs/lists-and-keys.html#keys

Lynelllynelle answered 14/12, 2020 at 22:41 Comment(0)
A
2

In my case, set id to tag

<tbody key={i}>

The problem is solved.

Ansel answered 14/4, 2021 at 19:41 Comment(0)
U
2

A visual explanation.

  1. The incorrect way key=index (of an array)

enter image description here

As you can see, label 3, label 2, and label 1 ALL got re-rendered (flashing in the Elements panel).

  1. The correct way key=uniqueId enter image description here

Only the top new element flashes (gets re-rendered).

Ut answered 20/8, 2022 at 2:9 Comment(0)
C
1

This is a warning, But addressing this will make Reacts rendering much FASTER,

This is because React needs to uniquely identify each items in the list. Lets say if the state of an element of that list changes in Reacts Virtual DOM then React needs to figure out which element got changed and where in the DOM it needs to change so that browser DOM will be in sync with the Reacts Virtual DOM.

As a solution just introduce a key attribute to each li tag. This key should be a unique value to each element.

Costumier answered 24/9, 2018 at 8:40 Comment(5)
This is not entirely correct. Rendering will not be faster if you add the key prop. If you don't provide one, React will assign one automatically (the current index of the iteration).Pleasant
@Pleasant in that case why it raise a warning ?Costumier
because by not providing a key, React doesn't know how your data is modelled. This can lead to undesired results if the array is modified.Pleasant
@Pleasant in that case of array modification, will React correct the indices according to that if we did not provide keys. Anyway I thought removing extra overhead from React will make some impact on the rendering process.Costumier
again, React will basically do key={i}. So it depends on the data your array contains. For example, if you have the list ["Volvo", "Tesla"], then obviously the Volvo is identified by the key 0 and the Tesla with 1 - because that is the order they will appear in the loop. Now if you reorder the array the keys are swapped. For React, since "object" 0 is still at the top, it will rather interpret this change as a "rename", rather than a reorder. The correct keys here would need to be, in order, 1 then 0. You don't always reorder mid runtime, but when you do, it's a risk.Pleasant
B
1
var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c, i) {
          return <td key={i}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

This will sove the problem.

Bighorn answered 25/11, 2019 at 9:57 Comment(0)
S
1
If you are getting error like :

> index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `Home`. See https://reactjs.org/link/warning-keys for more information.

Then Use inside map function like:

  {classes.map((user, index) => (
              <Card  **key={user.id}**></Card>
  ))}`enter code here`
Serval answered 16/4, 2021 at 10:34 Comment(0)
H
1

This is a simple example,I have used a react condition with && first then map, in the I have added the key the user id to be sure that it's unique

 <tbody>
                                    {users &&
                                    users.map((user) => {
                                        return <tr key={user._id}>
                                            <td>{user.username}</td>
                                            <td><input
                                                name="isGoing"
                                                type="checkbox"
                                                checked={user.isEnabled}
                                                onChange={handleInputChangeNew}/></td>
                                            <td>{user.role.roleTitle} - {user.role.department.departmentName}</td>
                                            {/*<td className="text-right">
                                                    <Button>
                                                        ACTION
                                                    </Button>
                                                </td>*/}
                                        </tr>
                                    })
                                    }


                                    </tbody>
Halhalafian answered 25/8, 2021 at 18:41 Comment(0)
N
1

your key should be unique.like an unique id.And your code should be like this

<div>
 {products.map(product => (
   <Product key={product.id}>
    </Product>
    ))}
  </div>
Noteworthy answered 2/5, 2022 at 17:35 Comment(0)
H
1

According to React docs, each row/item should have a unique key.

Keys help React identify which items have changed, are added, or are removed.

Personally, I prefer using the crypto interface to generate a random UUID:
(crypto is built-in in vanilla-js)

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) =>
  <li key={crypto.randomUUID()}>item {number}
  </li>
);
Heavyweight answered 8/1, 2023 at 2:43 Comment(1)
With every render cycle, you are calling the randomizer to assign a new key to each li, forcing them to re-render. This is highly inefficient. Rather, you should ensure that the assigned ID does not change if the list item does not change.Corbel
D
1

I also had to deal with deletion and addition of children with no unique keys.

So I ended up using UUID as keys and wrapped them in useMemo based on the number of elements.

  const uniqueKeys = useMemo(() =>
    data.map(_ => uuidv4()),
    [data.length]
  );

  // in render
  {data.map((item, index) => (
     <Tr key={uniqueKeys[index]}>
Drennan answered 13/12, 2023 at 16:31 Comment(0)
A
1

I was puzzled by this until I looked very carefully at my code - so this is what I had - spot the bug:

{
  items.map(
    (item) => {
      
      return (<>
         <IonItem key={item.id}>
             <p>{ item.name }</p>
         </IonItem>
      </>);
    }
  )
}

So, I had a key attribute on my "item" component (<IonItem>) - still React complained about a lack of a unique key on my list items ...

The bug of course was that I erroneously wrapped the whole thing in <> and </> which do NOT have a key property ... once I removed this (unnecessary) <>...</> wrapper, the error disappeared.

Maybe this is obvious, but it's VERY easy to overlook ... it had me puzzled for a while.

Amido answered 25/12, 2023 at 5:58 Comment(0)
T
0

I don't go with the detail explanation but the key to this answer is "key" just put the key attribute in your tag and ensure that every-time you iterate you give unique value to it

#ensure that the key's value is not clashing with others

Example

<div>
        {conversation.map(item => (
          <div key={item.id  } id={item.id}>
          </div>
        ))}
      </div>

where the conversation is an array of something like below :

  const conversation = [{id:"unique"+0,label:"OPEN"},{id:"unique"+1,label:"RESOLVED"},{id:"unique"+2,label:"ARCHIVED"},
   ]
Trev answered 16/9, 2021 at 12:9 Comment(0)
S
0

I think when working with tables (or in similar examples), creating a unique key should be passed to the child component from the parent component for the sake of REUSABILITY.

Because if you are creating a table, that means you are passing data from the parent. If you assign key={row.name} maybe currently data has name property but if you want to use this table component somewhere else you assume that in each row of data that you have passed, you have name property.

Since the engineer will be preparing the data in the parent component, the engineer should create a key function based on the data.

const keyFunc = (student) => {
    return student.id;
  }; 

In this case, the engineer knows what data it is sending, it knows that each row has an id property that is unique. Maybe in the different data set, the data set is stock prices and it does not have "id" property but "symbol"

 const keyFunc = (stock) => {
        return stock.symbol;
      }; 

this keyFunc should be passed to the child component as a prop to guarantee reusability and uniqueness.

Simonides answered 25/12, 2022 at 21:57 Comment(0)
H
0

I've seen many times people rendering fragments <></> and it generates this issue. Try to change the fragments to null or a component with a unique key

Hekker answered 13/8, 2023 at 1:31 Comment(0)
E
0

For React official docs

The key should be inside <li key={person}>{person}</li>


const people = [
  'Creola Katherine Johnson: mathematician',
  'Mario José Molina-Pasquel Henríquez: chemist',
  'Mohammad Abdus Salam: physicist',
  'Percy Lavon Julian: chemist',
  'Subrahmanyan Chandrasekhar: astrophysicist'
];

export default function List() {
  const listItems = people.map(person =>
    <li key={person}>{person}</li>
  );
  return <ul>{listItems}</ul>;
}


Earwig answered 29/10, 2023 at 17:55 Comment(0)
A
0

Here is sample code (App.jsx), just use it to your file

const ListItem = (props) => (
  <li>
    <input type="checkbox" />
    <p> {props.title} </p>
  </li>
);

const productList = [
  {
    id: 1,
    title: 'Shirt',
    checked: false
  },
  {
    id: 2,
    title: 'Pant',
    checked: false
  },
  {
    id: 3,
    title: 'Cap',
    checked: false
  },
]

function App(props) {
  return (
    <>
      <div>
        <ul>
          {productList.map((item) => (
            <ListItem key={item.id} title={item.title} />
          ))}
        </ul>
      </div>
    </>
  )
}

export default App
Atmo answered 6/11, 2023 at 15:50 Comment(0)
W
-1

If you are struggling with this error Each child in a list should have a unique "key" prop.

Solve by declaring index value to the key attribute inside the rendering element.

App.js component

import Map1 from './Map1';

const arr = [1,2,3,4,5];

const App = () => {
  return (
    <>
     
     <Map1 numb={arr} />     

    </>
  )
}

export default App

Map.js component

const Map1 = (props) => {

    let itemTwo = props.numb;
    let itemlist = itemTwo.map((item,index) => <li key={index}>{item}</li>)

    return (
        <>        
        <ul>
            <li style={liStyle}>{itemlist}</li>
        </ul>
        </>
    )
}

export default Map1
Wingover answered 14/1, 2022 at 4:24 Comment(0)
C
-2

The "Each child in a list should have a unique "key" prop." warning happens in React when you create a list of elements without the special key attribute. Keys must be assigned to each element in a loop to give stable identity to elements in React.

We can set the id property of the object as a unique key.

export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 return (
<div>
    <ul>
        {posts.map(value => 
            <li key={value.id}>{value.title}</li>
        )}
    </ul>
</div>
 );}


//simple way

//if u using ant design remove the empty fragment...

//worng ans---> change to following crt ans

export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 {fields.map((field,index)=>{
return(
  <> //empty fragment
   <Row key={index}>
    <Col span={6}>hello</Col>
   </Row>
  </>
)
})}

 //correct ans
//remove the empty fragments after solve this key.prop warning problem
export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 {fields.map((field,index)=>{
return(
  <> //empty fragment
   <Row key={index}>
    <Col span={6}>hello</Col>
   </Row>
  </>
)
})}
Cumberland answered 9/1, 2023 at 17:34 Comment(1)
I may be incorrect but the key needs to be on the highest element that's iterated over, so if you're including the fragments they'd need to be changed to <React.Fragment key={index}><React.Fragment />. Sadly you can't include a key in an empty fragment. But I don't think they're necessary as there's only one parent element inside the mapBrainy
G
-4

I faced a similar problem but not exact. Tried every possible solution and couldn't get rid of that error

Each child in an array should have a unique "key" prop.

Then I tried opening it in a different local host. I don't know how, but it worked!

Genetics answered 26/7, 2021 at 14:49 Comment(1)
This is most likely an issue with browser cache. You can hard-refresh on the same local host to remove any stored cache.Yarbrough

© 2022 - 2024 — McMap. All rights reserved.