Choose
Render different JSX when conditions change.
React uses ordinary JavaScript to decide which elements appear and to turn collections of data into repeated UI. Stable keys help React track each item as the collection changes.
These ideas often work together: choose the data, transform it into elements, and give each repeated element a durable identity.
Render different JSX when conditions change.
Use array methods to create one element per item.
Give siblings keys that remain tied to their data.
A component can return different JSX for different data. React does not add a special conditional syntax. Use JavaScript before the return, or use expressions inside JSX.
if and an early returnUse this when an entire branch of the component changes. It is often the clearest choice for loading, error, and empty states.
Use condition ? a : b when exactly one of two values should appear in the same location.
Use condition && element when something should either appear or render nothing.
function UserPanel({ user, isLoading, error }) {
if (isLoading) {
return <p>Loading profileā¦</p>;
}
if (error) {
return <p>Could not load the profile.</p>;
}
return (
<section>
<h2>{user.name}</h2>
{user.isAdmin ? <AdminTools /> : <MemberTools />}
{user.hasAlerts && <AlertBadge />}
</section>
);
}
Watch for zero with &&. React renders numbers, so {items.length && <List />} renders 0 when the array is empty. Write {items.length > 0 && <List />} to make the condition a boolean.
null when a component should render nothing.function Warning({ message }) {
if (!message) {
return null;
}
return <p role="alert">{message}</p>;
}
Data usually arrives as an array. Use map() to transform each item into JSX. If only some items should appear, use filter() first or conditionally return null from the mapping callback.
filter() keeps the objects you need.map() returns JSX for each object.const tasks = [
{ id: 101, title: "Sketch the layout", done: true },
{ id: 102, title: "Build the header", done: false },
{ id: 103, title: "Check keyboard access", done: true },
];
function CompletedTasks() {
const completed = tasks.filter(task => task.done);
return (
<ul>
{completed.map(task => (
<li key={task.id}>{task.title}</li>
))}
</ul>
);
}
An arrow callback that returns multi-line JSX needs parentheses after =>. If you add braces instead, write an explicit return.
A key is a string or number that identifies one element among its siblings. During the next render, React uses keys to match old items with new items, even if items move, arrive, or disappear.
The same key may be reused in a different array, but two items in one rendered list must not share it.
Use an ID from the data. Do not create a key during rendering with Math.random() or a changing timestamp.
The key should describe the data object's identity, not its current position in the array.
| Key choice | When it works | Risk |
|---|---|---|
key={task.id} | Best default for data with durable IDs | Low |
key={index} | Only for a truly fixed list that never reorders, inserts, or deletes | State can follow the wrong item after changes |
key={Math.random()} | Never for normal list rendering | Items are recreated on every render |
map(), not on a nested child.function TaskList({ tasks }) {
return (
<ul>
{tasks.map(task => (
<TaskRow key={task.id} task={task} />
))}
</ul>
);
}
function TaskRow({ task }) {
return <li>{task.title}</li>;
}
key is not a prop. React consumes it as identity metadata, so TaskRow cannot read props.key. Pass the value separately, such as <TaskRow key={task.id} taskId={task.id} />, when the child also needs it.
An if with an early return is usually clearest. It handles the loading branch before the component reaches its main return.
The index describes a position, not an item. After a reorder, the same index may point to different data, so React can preserve local state or DOM state on the wrong row.
map() returns <TaskRow />?
Place it on <TaskRow />, the element returned directly from the callback. A key inside the component is too deep to identify that sibling in the array.