93

I am new to React, and I'm trying to output a table containing the information of users. But Eslint is keep giving me the following error:

[eslint] Missing "key" prop for element in iterator [react/jsx-key]

I am not sure if I did this properly, but I have assigned a unique ID number for each person in the user list, but not sure why the error is persistent.

So in my PeopleCard.js I have the following:

import React from "react";
import {
  Card,
  CardImg,
  CardText,
  CardBody,
  CardTitle,
  CardSubtitle,
  Button
} from "reactstrap";
import PropTypes from "prop-types";

class PeopleCard extends React.Component {
  static propTypes = {
    person: PropTypes.object,
    id: PropTypes.number,
    name: PropTypes.string,
    company: PropTypes.string,
    description: PropTypes.string
  };
  render() {
    return (
      <div>
        <Card>
          <CardImg
            top
            width="100%"
            src="https://via.placeholder.com/318x180.png"
            alt="Card image cap"
          />
          <CardBody>
            <CardTitle>{this.props.person.name}</CardTitle>
            <CardSubtitle>{this.props.person.company}</CardSubtitle>
            <CardText>{this.props.person.description}</CardText>
            <Button>Button</Button>
          </CardBody>
        </Card>
      </div>
    );
  }
}

export default PeopleCard;

And in my MainArea.js, I have the following:

import React from "react";
import { Container, Row, Col } from "reactstrap";
import PeopleCard from "./PeopleCard";

class MainArea extends React.Component {
  constructor() {
    super();
    this.state = {
      people: [
        {
          id: 1,
          name: "John",
          company: "Some Company, Inc",
          description: "Met at a party."
        },
        {
          id: 2,
          name: "Mary",
          company: "Some Company, Inc",
          description: "Met at a party."
        },
        {
          id: 3,
          name: "Jane",
          company: "Some Company, Inc",
          description: "Met at a party."
        }
      ]
    };
  }
  render() {
    let peopleCard = this.state.people.map(person => {
      return (
        <Col sm="4">
          <PeopleCard key={person.id} person={person} />
        </Col>
      );
    });
    return (
      <Container fluid>
        <Row>{peopleCard}</Row>
      </Container>
    );
  }
}

export default MainArea;

The following line is throwing the error, and I cannot figure out why:

<Col sm="4">
   <PeopleCard key={person.id} person={person} />
</Col>

How can I prevent this error from appearing?

3 Answers 3

125

You should put the key on the outer element inside the loop:

const peopleCard = this.state.people.map(person => (
  <Col key={person.id} sm="4">
    <PeopleCard person={person} />
  </Col>
));

If in some rarer cases you have two elements then you can put the key on a React.Fragment:

const peopleCard = this.state.people.map(person => (
  <React.Fragment key={person.id}>
    <Col key={person.id} sm="4">
      <PeopleCard person={person} />
    </Col>
    <SomeOtherElement />
  </React.Fragment>
));
3
  • 8
    @538ROMEO check this post, it's short and straight to the point why it's useful: medium.com/@adhithiravi/… Commented Feb 4, 2020 at 13:08
  • 2
    @538ROMEO why would it make sense not to? React uses the key to identify the outer element so it can re-use the DOM node on updates even if it's moved. It shouldn't have to search arbitrarily deeper in your tree and guess that some key it encounters is ok and unique to use for a different part of the tree higher up
    – nanobar
    Commented Jun 2, 2020 at 14:04
  • unclear and Failed . Commented Aug 31, 2022 at 8:32
4

It is always be the best practice to implement key when mapping elements. But sometimes it is kind of annoying to see this as an error instead of warning.

To turn the error into warning, you could add rules to your .eslintrc.cjs:

rules: {
  'react/jsx-key': [1, { checkFragmentShorthand: true }]
}
0

Sometimes it'll still give an issue if your two key/values get a match so better use it this way.

render() {
  let peopleCard = this.state.people.map((person, index) => {
    return (
      <Col sm="4" key={`${person.id}+${index}`}>
        <PeopleCard key={person.id} person={person} />
      </Col>
    );
  });
  return (
    <Container fluid>
      <Row>{peopleCard}</Row>
    </Container>
  );
}

Where no two loops will have the same id with index which can make the key/value different.

5
  • Unclear : You must have a key property for the HTML whom value is unique at each iteration of the loop. Commented Aug 31, 2022 at 9:06
  • yes, for that i am using person.id and index so that i can remain unique
    – lodey
    Commented Sep 2, 2022 at 9:27
  • 1
    You should not use index as key. Have look this article, which explains clearly why. Commented Nov 10, 2022 at 10:00
  • yes true but for now index is not a primary key, i am just using to patching it so there is no dependency with DOM element. It's true we shouldn't use index as key.
    – lodey
    Commented Feb 8, 2023 at 12:45
  • Keys must not change or that defeats their purpose. E.g. if the position of element person1+0 and person1+1 is swapped for some reason, React would still not know that, and might not update the list (because the keys index part of each item is changed as well to match the new order). -- You can argue this is a less likely error, but it's still a potential error (actually, I prefer errors that occur often over errors that occur rarely, so I'll find them and can fix them.)
    – kca
    Commented Dec 5 at 10:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.