Skip to content

Describing the UI

Fresh

React is a JavaScript library for rendering user interfaces. This section covers the fundamentals of describing what should appear on screen.

Your First Component

Components are the building blocks of React UI. A React component is a JavaScript function that returns markup:

jsx
function Profile() {
  return (
    <img
      src="https://example.com/avatar.jpg"
      alt="Katherine Johnson"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing Scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

Never Define a Component Inside Another Component

Defining a component inside another component is slow and causes bugs. Define every component at the top level.

Importing and Exporting Components

You can declare many components in one file, but large files become difficult to navigate. Use one component per file:

jsx
// Gallery.js
import Profile from './Profile.js';

export default function Gallery() {
  return (
    <section>
      <h1>Amazing Scientists</h1>
      <Profile />
    </section>
  );
}
jsx
// Profile.js
export default function Profile() {
  return <img src="https://example.com/avatar.jpg" alt="Katherine Johnson" />;
}
SyntaxExportImport
Defaultexport default function Btn() {}import Btn from './Btn.js'
Namedexport function Btn() {}import { Btn } from './Btn.js'

A file can have at most one default export, but can have multiple named exports.

JSX Rules

JSX looks like HTML but is stricter:

  1. Return a single root element. Wrap multiple elements in <div> or <>...</> (Fragment).
  2. Close all tags. Self-closing tags like <img> must become <img />.
  3. camelCase most attributes. class becomes className, for becomes htmlFor, stroke-width becomes strokeWidth.
jsx
export default function TodoList() {
  return (
    <>
      <h1>Hedy Lamarr's Todos</h1>
      <img
        src="https://example.com/hedy.jpg"
        alt="Hedy Lamarr"
        className="photo"
      />
      <ul>
        <li>Invent new traffic lights</li>
        <li>Rehearse a movie scene</li>
      </ul>
    </>
  );
}

JavaScript in JSX with Curly Braces

Curly braces {} let you use JavaScript inside JSX. You can use them in two places:

  1. As text directly inside a JSX tag: <h1>{name}'s To Do List</h1>
  2. As attributes: src={avatar}
jsx
const today = new Date();

function formatDate(date) {
  return new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(date);
}

export default function TodoList() {
  return <h1>To Do List for {formatDate(today)}</h1>;
}

Double curlies are not special syntax. They are a JavaScript object inside JSX curly braces:

jsx
<ul style={{ backgroundColor: 'black', color: 'pink' }}>

Passing Props to a Component

React components communicate through props. Every parent component can pass information to its child components.

jsx
function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={person.imageUrl}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <Avatar
      person={{ name: 'Lin Lanying', imageUrl: 'https://example.com/lin.jpg' }}
      size={100}
    />
  );
}

Default Props

Specify a default value with destructuring:

jsx
function Avatar({ person, size = 100 }) {
  // size is 100 if not passed
}

Forwarding Props with Spread

jsx
function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}

Children Prop

When you nest content inside a JSX tag, the parent receives it as children:

jsx
function Card({ children }) {
  return <div className="card">{children}</div>;
}

export default function Profile() {
  return (
    <Card>
      <Avatar />
    </Card>
  );
}

Conditional Rendering

Use JavaScript if, ternary ? :, or logical &&:

jsx
function Item({ name, isPacked }) {
  // With if
  if (isPacked) {
    return <li className="item">{name} done</li>;
  }
  return <li className="item">{name}</li>;
}

// With ternary
function Item2({ name, isPacked }) {
  return <li className="item">{isPacked ? <del>{name}</del> : name}</li>;
}

// With && (renders right side only if left side is true)
function Item3({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && 'done'}
    </li>
  );
}

Don't Put Numbers on the Left of &&

messageCount && <p>New messages</p> renders 0 when messageCount is 0, not nothing. Use messageCount > 0 && ... instead.

Rendering Lists

Use filter() and map() to filter and transform arrays into lists of components:

jsx
const people = [
  { id: 0, name: 'Creola Katherine Johnson', profession: 'mathematician' },
  { id: 1, name: 'Mario Jose Molina', profession: 'chemist' },
  { id: 2, name: 'Mohammad Abdus Salam', profession: 'physicist' },
];

export default function List() {
  const chemists = people.filter(person => person.profession === 'chemist');
  const listItems = chemists.map(person =>
    <li key={person.id}>{person.name}</li>
  );
  return <ul>{listItems}</ul>;
}

Keeping Components Pure

A pure component:

  • Minds its own business: does not change any objects or variables that existed before rendering
  • Same inputs, same output: given the same inputs, always returns the same JSX
jsx
// BAD: Impure, modifies external variable
let guest = 0;
function Cup() {
  guest = guest + 1; // mutating external variable!
  return <h2>Tea cup for guest #{guest}</h2>;
}

// GOOD: Pure, uses props
function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

Side Effects

React's rendering must always be pure. Side effects (changing the DOM, starting timers, making API calls) should happen in event handlers or effects, not during rendering.

Your UI as a Tree

React models your UI as a tree of components. The render tree captures the nesting relationship between components, which helps you understand data flow and rendering performance.

flowchart TD
    App --> Header
    App --> Main
    App --> Footer
    Main --> Sidebar
    Main --> Content
    Content --> Article
    Content --> Comments

The module dependency tree maps how your source files import each other. Build tools use this tree to bundle all the JavaScript needed to render your app.