Learnitweb

Rendering lists in React

1. Introduction

You will often want to show multiple similar components from a collection of data. You can use JavaScript array methods combined with filter() and map() to filter and transform array data to components.

2. Rendering data from arrays

Suppose you have a list of fruits.

<ul>
  <li>Apple</li>
  <li>Mango</li>
  <li>Orange</li>
  <li>Grapes</li>
  <li>Banana</li>
</ul>

This is a simple example of list of items. You may often need to show similar components with different data. In such scenarios, you can save the data in JavaScript objects and arrays, then utilize methods like map() and filter() to generate and display lists of components.

Here’s a short example of how to generate a list of items from an array:

const fruits = ["Apple", "Mango", "Orange", "Grapes", "Banana"];

export default function List() {
  const listItems = fruits.map((fruit) => 
  <li>{fruit}</li>
  );
  return <ul>{listItems}</ul>;
}

If you check the console in the browser, you’ll see the following error:

Warning: Each child in a list should have a unique "key" prop.

Check the render method of `List`. See https://reactjs.org/link/warning-keys for more information.
    at li
    at List
    at ul
    at App

3. Keeping list items in order with key

You need to provide a key to each item in the array. A key can be a string or a number that uniquely identifies it among other items in the array.

<li key={employye.id}>...</li>

Note: JSX elements directly inside a map() call always need keys!

Keys should not be generated on the fly and should be based on your data like employee ID.

Using key, React knows which item in the array corresponds to which component. This becomes important when the items in the array change their order (e.g. due to sorting), get inserted or deleted. Using key, React can find out what happened to a particular item and can properly update the DOM tree.

The earlier list example can be modified to add the employee ID as the key.

export default function List() {
  const salesPeople = employees.filter((employee) => employee.department === "Sales");
  const listItems = salesPeople.map((employee) => <li key={employee.id}>{employee.name}</li>);
  return <ul>{listItems}</ul>;
}

Fragments disappear from the DOM, so this will produce a flat list of <h1>, <p>, <h1>, <p>, and so on.

4. Why does React need keys?

A key allows React to uniquely identify an item among its siblings. A carefully selected key offers more information than just the item’s position in the array. Even if the order changes, the key enables React to track the item throughout its lifecycle.
React uses an item’s index in the array as its key if you don’t specify a key at all. You should not use generate keys on the fly, e.g. with key={Math.random()}. Instead, use a stable ID based on the data.

5. Rules of keys

  • Keys need to be unique within a single array of siblings. However, it’s acceptable to reuse the same keys for JSX nodes across different arrays.
  • Keys must not change while rendering.

6. How to get ‘key’

A key can be generated from the unique key from the database for example, a student’s enrollment number, employee ID etc. If your data is generated locally and persisted locally, you can incrementally generate the keys using the methods like crypto.randomUUID().

7. Filtering arrays of items

Suppose you have a list of employees of different departments.

const employees = [
  {
    id: 0,
    name: "Roger",
    department: "Sales",
  },
  {
    id: 1,
    name: "John",
    department: "Finance",
  },
  {
    id: 2,
    name: "James",
    department: "Sales",
  },
  {
    id: 3,
    name: "Tom",
    department: "Finance",
  },
  {
    id: 4,
    name: "Holland",
    department: "Sales",
  },
];

You want to filter and show only the employees working in Sales department. You can first filter the Sales employees and then use map() to transform the data to list items.

const employees = [
  {
    id: 0,
    name: "Roger",
    department: "Sales",
  },
  {
    id: 1,
    name: "John",
    department: "Finance",
  },
  {
    id: 2,
    name: "James",
    department: "Sales",
  },
  {
    id: 3,
    name: "Tom",
    department: "Finance",
  },
  {
    id: 4,
    name: "Holland",
    department: "Sales",
  },
];

export default function List() {
  const salesPeople = employees.filter((employee) => employee.department === "Sales");
  const listItems = salesPeople.map((employee) => <li>{employee.name}</li>);
  return <ul>{listItems}</ul>;
}

Arrow functions implicitly return the expression right after =>, so you didn’t need a return statement:

const listItems = employees.map(person =>
  <li>...</li> // Implicit return!
);

However, you must write return explicitly if your => is followed by a { curly brace.

const listItems = employees.map(employee => { // Curly brace
  return <li>...</li>;
});

Arrow functions containing => { are said to have a “block body”. They let you write more than a single line of code, but you have to write a return statement yourself. If you forget it, nothing gets returned!

8. Conclusion

In this tutorial, we’ve explored how to render lists in React, covering various techniques and best practices to ensure efficient and maintainable code.