sherpaurgen
sherpaurgen

Reputation: 3274

understanding react props and keys

React newbie here. Im referring this and following traversy react videos and i have customized my app with bootstrap4.5. I understand unique key must be passed for performance and help React identify changed items. I have Users.js

1  const Users = (props) => {
2    //class changed to arrow functions
3    if (props.loading) {
4        return <Spinner />
5    }
6    else {
7        return (
8            <div className="row">
9                {props.users.map((user) => (
10                    <div className="col-sm-3 mt-3"  >
11                        <UserItem key={user.id} user={user} />
12                    </div>
13                ))}
14            </div >
15        );
16    }
17 }

in above code i get the error in console below:

Warning: Each child in a list should have a unique "key" prop. Check the render method of `Users`. See https://reactjs.org/docs/lists-and-keys.html#keys for more information.

if i change lines 10 and 11 like below, the error is no longer there

10                    <div key={user.id} className="col-sm-3 mt-3"  >
11                        <UserItem  user={user} />

Whats the reason behind this and is it fine to pass key like this since it works ?

The list looks like below which is passed in props

[
    {
      "login": "mojombo",
      "id": 17,
      "avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
      "url": "https://api.github.com/users/mojombo",
      "html_url": "https://github.com/mojombo"
    },
    {
        "login": "wintersword",
        "id": 18,
        "avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
        "url": "https://api.github.com/users/mojombo",
        "html_url": "https://github.com/mojombo"
      }
]

react version : "16.13.1"

Upvotes: 2

Views: 81

Answers (4)

Yousaf
Yousaf

Reputation: 29282

key should be added on the outer most element in the hierarchy of jsx code that is created using a loop

From the docs:

Keys only make sense in the context of the surrounding array

To understand it better, lets look at an example.

Suppose you are rendering li elements using a loop.

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

in this case, key should be on the li element. Now if you extract li element in another component, lets say ListItem

function ListItem({ text }) {
    return (
       <li>{ text }</li>
    );
}

then your loop will be changed as

const list = tasks.map((t, index) =>
  <ListItem key={index} text={t}>
);

In this case, you place the key on ListItem and the key will be associated with the element you added it on and all the elements nested inside ListItem.

Please note that in above examples, i have used index as key. You should only use index as key if you don't have any other unique value to use as key.

Upvotes: 1

abhikumar22
abhikumar22

Reputation: 1814

“Props" is a special keyword in React, which stands for properties and is being used for passing data from one component to another. But the important part here is that data with props are being passed in a uni-directional flow. (one way from parent to child) Furthermore, props data is read-only, which means that data coming from the parent should not be changed by child components.

So if you have to access the first element, then you can access like below props.users[0] - > Gives the first element in the JSON array and props.users[1] so on

props.users[0]
{
      "login": "mojombo",
      "id": 17,
      "avatar_url": "https://avatars0.githubusercontent.com/u/1?v=4",
      "url": "https://api.github.com/users/mojombo",
      "html_url": "https://github.com/mojombo"
}

Now,

1  const Users = (props) => {
2    //class changed to arrow functions
3    if (props.loading) {
4        return <Spinner />
5    }
6    else {
7        return (
8            <div className="row">
9                {props.users.map((user,index) => (  --> Change here
10                    <div className="col-sm-3 mt-3"  >
11                        <UserItem 
                                key={index} --> Change here
                                user={user} 
                            />
12                    </div>
13                ))}
14            </div >
15        );
16    }
17 }

Since, map funtion will iterate your whole array, so when redering it to return some view you have to give some uniqueness column or value to key variable so that react will know the number of different divs to render.

References : https://itnext.io/what-is-props-and-how-to-use-it-in-react-da307f500da0

Upvotes: 0

Maniraj Murugan
Maniraj Murugan

Reputation: 9084

Change,

{props.users.map((user) => (
  <div className="col-sm-3 mt-3"  >
    <UserItem key={user.id} user={user} />
  </div>
))}

To

{props.users.map((user) => (
  <div className="col-sm-3 mt-3" key={user.id}>
    <UserItem user={user} />
  </div>
))}

Here the key={user.id} needs to be in div element which is the immediate parent element of map method..

-> The key prop has to be in the parent element under map method which refers to all the sibilings..

-> Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity and it needs to be in immediate parent element.

-> The outermost/parent element returned by the map function needs to have a key prop with unique value.

Here in your code,

Parent Element:

<div className="col-sm-3 mt-3" key={user.id}>

has the sibiling,

<UserItem key={user.id} user={user} />

So parent element needs to identified with unique value in key prop..

Upvotes: 1

Mukesh Keshu
Mukesh Keshu

Reputation: 467

<UserItem key={user.id} user={user} /> implies that you are passing the key as props to the child element UserItem.

But what you actually did by providing key to div is correct.

Assuming {user.id} is unique for each user , using that on your div <div key={user.id} className="col-sm-3 mt-3" > ensures that your div always have a unique key when the list is looped..

Upvotes: 0

Related Questions