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.
Explain
Turn student records into a JSX list with map.
Trace
Choose a stable student ID as the key for each sibling row.
Apply
Predict the identity problem caused by index keys when rows move.
Lists and Keys: follow the relationship
Records have identity
Student IDs belong to records and survive sorting.
Rows carry keys
Each returned row uses its record’s stable ID as a key.
React matches rows
Matching identity keeps an existing row associated with its student.
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 RaviConnect 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: 40Check your reasoning
Choose the explanation that matches React and JavaScript behavior. Review the reasoning for each alternative before moving on.
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.