Rendering Lists

Difficulty: Beginner

Rendering lists of data is one of the most common tasks in React. You take an array of data and transform it into an array of React elements using the `Array.map()` method. For example, `{users.map(user => <UserCard key={user.id} name={user.name} />)}` transforms each user object into a UserCard component. The map method returns a new array of elements that React knows how to render.

The `key` prop is a special attribute that React requires when rendering lists. Keys tell React which items in the list have changed, been added, or been removed. Without keys, React has to re-render every item in the list when the data changes. With keys, React can match items between the old and new list, only updating what actually changed. This makes list updates much more efficient.

Keys must be unique among siblings - they do not need to be globally unique, just unique within the same list. The best key is a stable identifier from your data, such as a database ID. Keys should be stable (not change between renders), predictable (derived from the data, not random), and unique (no duplicates in the same list). Never use `Math.random()` as a key - it changes every render, defeating the entire purpose.

Using the array index as a key (`items.map((item, index) => <li key={index}>)`) is a common practice but is problematic in many cases. Index keys work fine if the list is static and never reordered. But if items can be added, removed, or reordered, index keys cause bugs: React will match elements by position rather than identity, leading to stale state, incorrect animations, and input values appearing in the wrong items. Always prefer stable IDs over indices.

When you do not provide keys, React will warn you in the development console. While the list will still render, React cannot optimize updates and may produce incorrect results when the list changes. Keys are passed as a prop but are not accessible inside the component via `props.key` - React uses them internally and strips them from props. If you need the ID inside the component, pass it as a separate prop: `<Item key={id} id={id} />`.

Code examples

Basic List Rendering with map()

const fruits = ['Apple', 'Banana', 'Cherry', 'Date'];

// Transform data into elements using map
const elements = fruits.map((fruit, index) => ({
  key: 'fruit-' + index,
  type: 'li',
  props: { children: fruit }
}));

elements.forEach(el => {
  console.log(el.key + ': ' + el.props.children);
});

console.log('Total items: ' + elements.length);

Array.map() transforms each data item into an element. Each element gets a key prop so React can track it efficiently.

Why Keys Matter

// Without proper keys, React can't track items correctly
const before = [
  { id: 'a', text: 'First' },
  { id: 'b', text: 'Second' },
  { id: 'c', text: 'Third' }
];

// After reorder: item 'b' moved to front
const after = [
  { id: 'b', text: 'Second' },
  { id: 'a', text: 'First' },
  { id: 'c', text: 'Third' }
];

// With ID keys: React knows 'b' moved, only repositions it
console.log('With ID keys:');
after.forEach(item => console.log('  key=' + item.id + ': ' + item.text));

// With index keys: React thinks ALL items changed content
console.log('With index keys:');
console.log('  index 0: was First, now Second (wrong update!)');
console.log('  index 1: was Second, now First (wrong update!)');
console.log('  index 2: Third stays (ok)');

Stable ID keys let React track which item is which, even after reordering. Index keys cause React to see content changes instead of position changes.

Rendering Complex Lists

const users = [
  { id: 'u1', name: 'Alice', role: 'admin', active: true },
  { id: 'u2', name: 'Bob', role: 'user', active: false },
  { id: 'u3', name: 'Charlie', role: 'user', active: true }
];

// Render with filtering and transformation
const activeUsers = users
  .filter(u => u.active)
  .map(u => ({
    key: u.id,
    display: u.name + ' (' + u.role + ')'
  }));

console.log('Active users:');
activeUsers.forEach(u => console.log('  [' + u.key + '] ' + u.display));

// Render all users with conditional styling
const allUsers = users.map(u => ({
  key: u.id,
  display: u.name + (u.active ? ' - Active' : ' - Inactive')
}));

console.log('All users:');
allUsers.forEach(u => console.log('  ' + u.display));

You can chain filter and map to render subsets of data. Always use stable IDs from your data as keys, not generated values.

Key points

Concepts covered

Array.map(), key prop, why keys matter, list rendering, unique identifiers