ProgramGuru

Rendering Lists and Keys

Rendering Lists and Keys

A class contains many students, and the roster may change when students join or leave. We need to transform records into repeated interface rows while preserving which row belongs to which student.

Use map to convert an array into an array of React elements. Add a stable key to the outer element returned for each record. A key tells React which sibling item corresponds to which record between renders.

  1. Explain

    Turn student records into a JSX list with map.

  2. Trace

    Choose a stable student ID as the key for each sibling row.

  3. Apply

    Predict the identity problem caused by index keys when rows move.

Lists and Keys: follow the relationship

  1. Records have identity

    Student IDs belong to records and survive sorting.

  2. Rows carry keys

    Each returned row uses its record’s stable ID as a key.

  3. React matches rows

    Matching identity keeps an existing row associated with its student.

Read this relationship alongside the complete code. This diagram explains the flow; it does not execute React.

Build the mental model

Treat identity separately from position. Asha remains student s1 even if a new student appears before her. Her array index changes but her identity does not. Database identifiers or stable locally assigned IDs are better keys than positions for changing lists.

Keys belong to a sibling collection

Two separate lists can each contain a record with key s1. The requirement is uniqueness among siblings in that collection rather than universal uniqueness across the whole page. When returning a custom StudentRow, place the key on StudentRow at the map site, not on a nested element inside it.

When one record needs several sibling elements, a keyed Fragment can group them without adding a visible container. The shorthand fragment syntax cannot accept a key. Use a meaningful wrapper when it improves semantics, or import Fragment when grouping is the only requirement.

Read the complete React example

The example creates one li per record. The key is attached directly to li because li is the outer element returned by map. The practice filters by mark before mapping, so only passing students become rows. Filtering does not remove the need for keys.

React · JavaScript with JSX

import React from 'react';
export default function App() {
  const students = [{ id: 's1', name: 'Asha' }, { id: 's2', name: 'Ravi' }];
  return <main><h1>Class roster</h1><ul>{students.map(student => <li key={student.id}>{student.name}</li>)}</ul></main>;
}

Expected screen and behavior

Initial screen: Class roster Asha Ravi

Connect the source to the screen

React · main example

import React from 'react';
export default function App() {
  const students = [{ id: 's1', name: 'Asha' }, { id: 's2', name: 'Ravi' }];
  return <main><h1>Class roster</h1><ul>{students.map(student => <li key={student.id}>{student.name}</li>)}</ul></main>;
}

React compares sibling keys to match old and new items. Stable identity matters for stateful rows such as editable names. A key is not passed to a component as an ordinary prop; pass studentId separately if the row’s logic needs to read the identifier.

Avoid the common mistakes

Do not generate random keys during render. That tells React that every row is a different item on every render, potentially resetting state and losing focus. Index keys can be acceptable for fixed lists but are unsafe when records reorder, insert or delete.

Practice before reading the solution

React · starting example

import React from 'react';
export default function App() {
  const students = [{ id: 's1', name: 'Asha' }, { id: 's2', name: 'Ravi' }];
  return <main><h1>Class roster</h1><ul>{students.map(student => <li key={student.id}>{student.name}</li>)}</ul></main>;
}

Show the passing students from a three-student class.

Predict the initial visible text and explain which values determine it. Then inspect the worked solution below. Change one relevant input in your local project and check whether the screen follows your prediction. A working screen should be checked for the intended meaning, not merely the absence of an error.

Worked practice solution

The solution applies the inclusive pass boundary before rendering each matching record. Its IDs remain stable even though Ravi is absent from the filtered list. You can change a mark in the source and predict which record appears without changing the key policy.

React · JavaScript with JSX

import React from 'react';
export default function App() {
  const students = [{ id: 's1', name: 'Asha', marks: 45 }, { id: 's2', name: 'Ravi', marks: 32 }, { id: 's3', name: 'Meera', marks: 40 }];
  return <main><h1>Passing students</h1><ul>{students.filter(student => student.marks >= 40).map(student => <li key={student.id}>{student.name}: {student.marks}</li>)}</ul></main>;
}

Expected screen and behavior

Initial screen: Passing students Asha: 45 Meera: 40

Check your reasoning

Choose the explanation that matches React and JavaScript behavior. Review the reasoning for each alternative before moving on.

Which key best identifies a student in a roster that can reorder?
Choose one answer. You can try again.

Answer and explanation

The student’s persistent unique identifier

Correct. It identifies the record even when its position changes.

Use the idea in the next lesson

Use map to convert an array into an array of React elements. Add a stable key to the outer element returned for each record. A key tells React which sibling item corresponds to which record between renders.

Continue with Component Composition. Revisit Conditional Rendering when the relationship between inputs and the resulting screen needs another look.

Read the primary reference: React documentation on Rendering Lists and Keys.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Component Composition →