logoESLint React
Rules

no-unnecessary-key

This rule is experimental and may change in the future or be removed. It is not recommended for use in production code at this time.

Full Name in @eslint-react/eslint-plugin

@eslint-react/no-unnecessary-key

Full Name in eslint-plugin-react-x

react-x/no-unnecessary-key

Features

๐Ÿงช

Description

Disallows unnecessary key props on elements.

When rendering a list of elements in React, the key prop should only be placed on the outermost element for each item in the list. Adding keys to nested child elements is redundant, can cause confusion, and may lead to subtle bugs during refactoring.

For example, if an element with a key is wrapped with a React.Fragment or another component, the key must be moved to the new wrapping element. Forgetting to remove the original key from the child element can lead to runtime warnings from React if it's duplicated or simply leave unnecessary code. This rule helps identify and remove these redundant key props.

Also, static key props on elements that are not part of a dynamic structure (e.g., inside list rendering, conditional rendering, or control flow statements) are unnecessary and should be removed.

Examples

Failing

// A key on a child element inside a map is unnecessary
things.map(thing => (
  <div key={thing.id}>
    <p key="child-key">Hello</p> {/* This key is unnecessary */}
  </div>
))

// The key should be on the Fragment, not the div
things.map(thing => (
  <React.Fragment key={thing.id}>
    <div key={thing.id}> {/* This key is redundant */}
      {thing.name}
    </div>
    <div>{thing.description}</div>
  </React.Fragment>
))
// Static key on an element outside of a dynamic structure is unnecessary
function ComponentWithStaticKey() {
  return (
    <div>
      <MyComponent key="static-key" /> {/* This key is unnecessary */}
    </div>
  );
}

Passing

// Key is correctly placed on the top-level element of the map
things.map(thing => <div key={thing.id}>{thing.name}</div>)

// When using Fragments, the key is correctly placed on the Fragment
things.map(thing => (
  <React.Fragment key={thing.id}>
    <div>{thing.name}</div>
    <div>{thing.description}</div>
  </React.Fragment>
))

// Keys used to re-mount components are allowed
function ComponentWithDynamicKey({ someValue }) {
  return (
    <div>
      <MyComponent key={someValue} />
    </div>
  );
}

Additionally, keys are allowed in dynamic structures such as conditionals or control flow statements:

function ComponentWithControlFlow({items}) {
  const elements = [];
  for (const item of items) {
    elements.push(<MyComponent key={item.id} />);
  }
  return <div>{elements}</div>;
}

function ComponentWithControlFlow2({cond}) {
  if (cond) {
    return <MyComponent key="key" />;
  }
  return <MyComponent />;
}

Implementation

Further Reading


See Also

  • no-missing-key
    Prevents missing key on items in list rendering.
  • no-implicit-key
    Prevents key from not being explicitly specified (e.g., spreading key from objects).
  • no-array-index-key
    Warns when an array index is used as a key prop.
  • no-duplicate-key
    Prevents duplicate key props on sibling elements when rendering lists.

On this page