Write JSX, render conditionally, and turn arrays of data into lists of elements with stable keys.
Why it matters
JSX is the syntax you will write in every React component. It looks like HTML, but it is JavaScript underneath, and a few rules follow from that. Most React beginner bugs, such as a missing key, class instead of className or a stray object in the markup, come from not knowing what JSX really is.
JSX is JavaScript
This line:
const heading = <h1 className="title">Hello, {name}!</h1>;
is compiled (by Babel or a similar tool) into a plain function call:
const heading = React.createElement("h1", { className: "title" }, "Hello, ", name, "!");
The result is a React element: a small object describing what to show, not a real DOM node. React later turns the tree of elements into DOM. Because JSX is an expression, you can store it in variables, return it from functions and put it in arrays.
The rules that follow
- One parent. A component returns one element. Wrap siblings in a
<div>or an empty fragment<>...</>that adds nothing to the page. - Close every tag.
<img />,<br />,<input />. - camelCase attributes.
className(notclass),htmlFor(notfor),onClick,tabIndex. Inline styles take an object:style={{ color: "red" }}. - Curly braces hold JavaScript expressions.
{user.name},{price * 2},{formatDate(d)}. Statements such asiforforcannot go inside braces. - Component names start with a capital letter.
<BookList />is your component;<booklist />would be treated as an unknown HTML tag.
Conditional rendering
Since you cannot put if inside JSX, use plain JavaScript around it or an expression inside it:
function Status({ online }) {
if (!online) {
return <p>Offline</p>; // early return
}
return <p>Online</p>;
}
// Inside JSX:
<p>{count > 0 ? `${count} new messages` : "No new messages"}</p>
{isAdmin && <button>Delete</button>}
Careful with && and numbers: {items.length && <List />} renders a literal 0 when the list is empty. Write {items.length > 0 && <List />}.
React renders strings and numbers. It skips null, undefined, true and false, which is why && works. It throws an error if you try to render a plain object such as {user}; render {user.name} instead.
Turning data into elements
Real interfaces are mostly lists: products, messages, search results. You turn an array of data into an array of elements with map:
const books = [
{ id: 1, title: "Dune", author: "Frank Herbert" },
{ id: 2, title: "Kindred", author: "Octavia E. Butler" },
];
function BookList({ books }) {
return (
<ul>
{books.map((book) => (
<li key={book.id}>
<strong>{book.title}</strong> by {book.author}
</li>
))}
</ul>
);
}
{ books } in the parameter list reads the books value passed in as <BookList books={books} />. That is a prop, covered fully in the next lesson.
You can also filter or sort first. Use a copy before sorting, because sort changes the array in place: [...books].sort(...).
Keys
Each item in a list needs a key: a string or number that is unique among its siblings and stable over time. React uses keys to match items between renders, so when you insert, delete or reorder items it can keep each item's DOM and state attached to the right data.
- Good keys: database IDs, slugs, anything that belongs to the item.
- Risky keys: the array index. If the list is reordered or filtered, index 0 now points at different data, and inputs or animations can attach to the wrong row. Index keys are acceptable only for static lists that never change order.
- Never generate keys during render with
Math.random(): every render gets new keys, so React rebuilds every item.
The key goes on the outermost element returned from map, not on something inside it. React warns in the console ("Each child in a list should have a unique key prop") when one is missing.
Common mistakes
- Returning two sibling elements without a wrapper or fragment.
- Writing
class=orfor=; React warns and you should useclassNameandhtmlFor. - Forgetting to
returninside amapcallback with curly braces:books.map((b) => { <li>{b.title}</li> })returnsundefined. Use parentheses or an explicitreturn. - Putting the key on an inner element instead of the one
mapreturns.
Recap
- JSX compiles to
React.createElementcalls that create element objects. - Use
{}for expressions,className, closed tags and one root element (or a fragment). - Use early returns,
? :and&&for conditions. - Use
mapto turn arrays into elements, with a stable, uniquekeyon each item.
Try it
Open the Do tab. You will finish a BookList component that turns an array of books into list items with keys, and shows a message when the array is empty.