Lists And Keys In React

How to display lists of elements in React?

You can use map method to loop through an array of items and then use curly braces to insert it into your JSX code:

const todos = ["buy milk", "learn react", "walk the dog"];

const ToDoList = () => (
  <ul>
    {todos.map(todo => (
      <li>{todo}</li>
    ))}
  </ul>;
};

Here we mapped through the array of strings array using the array map() method. We return li element for each item. If you run this code - you’ll get a warning that you need to provide keys for your list items.

Providing Keys

React keeps track of the identity of each list item by it’s key attribute. Using this prop it determines what items were added, changed or removed.

It’s important that this key should be uniquely associated with each list item, ideally it should be some unique id:

const todos = [
    {text: "buy milk", id: 0},
    {text: "learn react", id: 1},
    {text: "walk the dog", id: 2}
];

const ToDoList = () => (
  <ul>
    {todos.map(todo => (
      <li key={todo.id}>
        {todo.text}
      </li>
    ))}
  </ul>;
};

If your items don’t have unique identifiers you can use map with index as last resort. It’s not optimal solution because this index won’t be bound to specific element and if the order of your element changes - the index will also change.

const todos = ["buy milk", "learn react", "walk the dog"];

const ToDoList = () => (
  <ul>
    {todos.map((todo, index) => (
      <li key={index}>{todo}</li>
    ))}
  </ul>;
};

It is important that keys would be unique among siblings, so in our example we can’t use todos values as keys. We can’t guarantee that our todos won’t have duplicates.

Using Lists With Components

In previous examples we were using li items, but in real React applications you’ll often use custom components inside your lists.

const todos = [
    {text: "buy milk", id: 0},
    {text: "learn react", id: 1},
    {text: "walk the dog", id: 2}
];

const ToDoList = () => (
  <ul>
    {todos.map((todo) => (
      <ToDoItem key={todo.id} text={todo.text} />
    ))}
  </ul>;
};

Keys are provided for elements inside of the loop, so you need to provide it inside of the component, or to component children:

const todos = [] // your todos

const ToDoItem = ({ text }) => <li key={text}>text</li>;
// THIS IS WRONG

const ToDoList = () => (
  <ul>
    {todos.map((todo) => (
      <ToDoItem key={todo.id} text={todo.text} />
    ))}
  </ul>;
};

Here is the correct example:

const todos = [] // your todos

const ToDoItem = ({ text }) => <li>text</li>;
// THIS IS WRONG

const ToDoList = () => (
  <ul>
    {todos.map((todo) => (
      <ToDoItem key={todo.id} text={todo.text} />
    ))}
  </ul>;
};

Recap

When you render lists in React you have to specify a special key prop for your items. It is required for React to effectively track changes in the list.

You should provide keys only to the outermost items inside your list, not their children. If you use custom components, like ToDoItem in our example - you should keep the key on the <ToDoItem /> elements, and not inside the component.

Keys should be unique across siblings in your list. In case if you can’t provide unique id’s you can use map() with index, but that’s not optimal and should be used only as last resort.