Outputting List Data
In React apps, list data is typically received as an array of values. Let's explore how to render these arrays into JSX elements and understand best practices for managing dynamic lists.
const products = [
{ id: 'p1', title: 'A Book', price: 59.99 },
{ id: 'p2', title: 'A Carpet', price: 129.49 },
{ id: 'p3', title: 'Another Book', price: 39.99 }
];
function ProductList({ products }) {
// ... todo
}
Outputting List Items Using a for...of
Loop
const productElements = [];
for (const product of products) {
productElements.push(
<li>
<h2>{product.title}</h2>
<p>${product.price}</p>
</li>
);
}
JSX elements are JavaScript values, so they can be stored in arrays and dynamically rendered.
return (
<ul>
{productElements}
</ul>
);
IMPORTANT
JSX arrays render all included elements as siblings in the DOM.
Equivalent syntax:
<div>
{[<p>Hi there</p>, <p>Another item</p>]}
</div>
Is the same as:
<div>
<p>Hi there</p>
<p>Another item</p>
</div>
Mapping List Data
The map()
method simplifies transforming arrays into JSX:
const users = [
{ id: 'u1', name: 'Max', age: 35 },
{ id: 'u2', name: 'Anna', age: 32 }
];
const userNames = users.map(user => user.name);
// Result: ['Max', 'Anna']
map()
method that can be called on any JavaScript array. It accepts a function as a parameter and executes that function for every array item. map()
then combines all these returned, transformed values into a new array and returns it.
Example in a React Component
function ProductsList({ products }) {
const productElements = products.map(product => (
<li>
<h2>{product.title}</h2>
<p>${product.price}</p>
</li>
));
return <ul>{productElements}</ul>;
}
Inline Mapping (Concise)
function ProductsList({ products }) {
return (
<ul>
{products.map(product => (
<li>
<h2>{product.title}</h2>
<p>${product.price}</p>
</li>
))}
</ul>
);
}
Using
.map()
is the standard approach to render lists in React.
Updating Lists
To update dynamic lists, you must modify the state immutably using the state-updating function from useState
.
Incorrect: Mutating the State Directly
const [todos, setTodos] = useState(
['Learn React', 'Recommend this book']
);
function handleAddTodo() {
todos.push('A new todo');
// React won't re-render
}
Even worse: State updating function should receive the new state as an argument. push()
method doesn’t return the updated array, it mutates the existing array in place.
function handleAddTodo() {
setTodos(todos.push('A new todo'));
// push returns the new length, not the array
}
IMPORTANT
While updating an array (or an object), perform update in an immutable way (i.e., without changing the original array or object). Instead, create a new array or object. This new array can be based on the old array and contain all the old data, as well as any new or updated data.
Correct: Using Immutability
Use the spread operator:
function handleAddTodo() {
setTodos(prevTodos => [...prevTodos, 'A new todo']);
}
Or use .concat()
:
function handleAddTodo() {
setTodos(prevTodos => prevTodos.concat('A new todo'));
}
NOTE
A function is passed to the state updater since the new state depends on the previous state.
The Problem with List Keys
Keys are simply unique identifier values that can (and should) be attached to JSX elements when rendering list data. Keys help React identify elements that were rendered before and didn’t change.
Without proper keys, React cannot efficiently update lists:
- React may re-render the entire list unnecessarily.
- Missing keys trigger warnings in development.
Solution: Add Unique key
Props
<li key={todo.id}>{todo.text}</li>
NOTE
Avoid using array indexes as keys unless you're certain items won't change order or be removed.
Index isn’t attached to the list item data. If you reorder items in a list, the index isn't reordered so stay the same.
Values Can Be Keys
const hobbies = ['Sports', 'Cooking'];
hobbies.map(hobby => <li key={hobby}>{hobby}</li>);
If list values are unique and stable, they can be used directly as keys.
Lists of JSX Elements
Use .map()
to render lists. Always provide a unique key
.
function Select({ items }) {
return (
<select>
{items.map((item) => (
<option key={item}>{item}</option>
))}
</select>
);
}
function App() {
const items = ["apples", "pears", "playstations"];
return <Select items={items} />;
}
Note:
key
is a special React prop used for efficient rendering. It should be unique within the list, ideally an ID or unique value, not just an index.
Fragments in JSX
Fragments let you group multiple elements without adding extra nodes to the DOM.
Long syntax:
import { Fragment } from 'react';
return (
<Fragment>
<h1>Hello</h1>
<a href="/blog">Blog</a>
</Fragment>
);
Short syntax:
return (
<>
<h1>Hello</h1>
<a href="/blog">Blog</a>
</>
);
Example: List with Fragment and key
Use <Fragment>
with key
when mapping JSX blocks:
function Breeds({ list }) {
return (
<dl>
{list.map(({ breed, description }) => (
<Fragment key={breed}>
<dt>{breed}</dt>
<dd>{description}</dd>
</Fragment>
))}
</dl>
);
}
function App() {
const list = [
{ breed: "Chihuahua", description: "Small breed of dog." },
{ breed: "Corgi", description: "Cute breed of dog." },
{ breed: "Cumberland Sheepdog", description: "Extinct breed of dog." }
];
return <Breeds list={list} />;
}
IMPORTANT
Use <Fragment>
when using key
Short syntax (<>...</>
) can’t accept props, so use <Fragment key={...}>
for list rendering.