Arrays in React 16 and the necessity of keys

Over the weekend at React Boston I saw a great talk by Ben Ilegbodu where he discussed changes in the upcoming Fiber release for React 16.

A common complaint in React 15 and below has been the inability to directly return an array of elements. React traditionally has required render functions to return a single top-level parent element. This means that when returning lists, you'd have to enclose the list in a container element:

// Valid React 15
const Page = () => (
  <div>
    <a href="#one">One</a>
    <a href="#two">Two</a>
  </div>
);

This often leads to extraneous markup with divs that pollute the HTML. In React 16, you can return arrays of elements:

// Valid React 16, invalid React 15
const Page = () => ([
  <a key="one" href="#one">One</a>
  <a key="two" href="#two">Two</a>
]);

You'll notice each element has a unique key. From the React docs:

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 — Lists and Keys

In practice, unique keys might look something like this:

// where href is guaranteed to be unique
const Header = ({ links }) => (
  <div>
    {links.map(link => (
      <a key={link.href} href={link.href}>{link.label}</a>
    ))}
  </div>
);

https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

Returning unique keys from the render method helps React identify what needs to be re-rendered. But it also adds some verbosity to the code that feels redundant; for instance, we don't need to add keys when returning top-level elements.

In his talk, Ben highlighted a library, react-aux, that addresses this verbosity problem and removes the need to provide explicit keys:

const Root = () => {
  return <Aux>
    <p>Hello, World!</p>
    <p>I am a demo for react-aux.</p>
  </Aux>;
};

// which is equivalent to the following:
const Root = () => {
  const Aux = (props) => props.children;

  return <Aux>
    <p>Hello, World!</p>
    <p>I am a demo for react-aux.</p>
  </Aux>;
};

Gajus Kuizinas's package leverages the fact that you can omit unique keys for a list of elements by directly returning children from a container div.

But that makes me question: **Why is it valid to return children without keys, but invalid to return a top level array without keys? **I suspect the answer has something to do with providing a top-level node for the children to live under. But why do nested siblings in a regular render function not require keys as well?

If you know the answer, please leave a comment! I'm hoping to dig more into React 16 and see if I can answer this myself.


Edit (9/29/2017): Looks like the team is thinking about addressing this in the future:

In the future, we'll likely add a special fragment syntax to JSX that doesn't require keys. — Andrew Clark

So there you have it!

I'm spending 2018 teaching myself AI and deep learning, and I'm journaling my adventure. Sign up below and I'll drop you a line when I publish new articles or find cool new tools.

Subscribe to the AI and Deep Learning Journal