Is the linter giving a false positive regarding unique keys?

Viewed 42
function renderRows(products) {
  return products.map(({ name, price, category, stocked }, index, currArr) =>
    // Is the category of the previous item in the array the same as the current item's category?
    currArr[index - 1]?.category === currArr[index].category ? (
      // If category is same, JUST render the product.
      <Row name={name} price={price} key={index} stocked={stocked} />
    ) : (
      // If it's a new category, render 2 rows...
      <>
        <Row category={category} key={"cat" + index} />
        <Row name={name} price={price} stocked={stocked} key={index} />
      </>
    )
  );
}

I have made a deliberate effort to separate out the key by throwing "cat" in front of one of the conditional renders.

React Dev Tools shows unique s

As we see React Dev Tools confirms that the s are unique.

Console error regarding non-unique s

Console shows this warning.

Now, if I do this without a conditional ternary render - no issues. Is there a better way to implement this? Is there something wrong with conditional render from inside map?

It shouldn't make difference, but here is the code for that mapped component, FYI.

const Row = ({ category, name, price, stocked }) => (
  <tr>
    {category ? (
      <td className="font-bold">{category}</td>
    ) : (
      <>
        <td className={stocked ? "" : "text-red-500"}>{name}</td>
        <td>{price}</td>
      </>
    )}
  </tr>
);

To add more context, here is the data set:

[
  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

And trying to render as shown in the docs here.

1 Answers

The fragment (<> short for <React.Fragment>) is missing the key, which is why the warning is displayed.

Try this:

function renderRows(products) {
  return products.map(({ name, price, category, stocked }, index, currArr) =>
    // Is the category of the previous item in the array the same as the current item's category?
    currArr[index - 1]?.category === currArr[index].category ? (
      // If category is same, JUST render the product.
      <Row name={name} price={price} key={index} stocked={stocked} />
    ) : (
      // If it's a new category, render 2 rows...
      <React.Fragment key={index}>
        <Row category={category} />
        <Row name={name} price={price} stocked={stocked} />
      </React.Fragment>
    )
  );
}

In the code above, I've expanded the fragment to include the key and removed the keys from the children of the fragment (as they are not required for anything).

Related