Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~28 min· topic 1 of 7

Topic 2.1

Components: Your Own Tags

In one line

A component is a JavaScript function whose name starts with a capital letter and which returns JSX; once defined, you use it like a new HTML tag, as many times as you want, and you always define it at the top level of a file, never inside another component.

Think of it like this

A cookie cutter. You make the cutter once, then press out as many cookies as you like, and every cookie has the same shape. A component is a cutter for a piece of screen. You write Avatar once, then put <Avatar /> on the page ten times and get ten avatars. Change the cutter and every cookie made from it changes too.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Component
A reusable piece of UI: a function with a capital-letter name that returns JSX.
Function component
A component written as a plain JavaScript function. This is how all modern React components are written.
PascalCase
Naming where every word starts with a capital letter: ProductCard, UserAvatar.
Instance
One use of a component on the page. Three <Avatar /> tags make three instances.
Parent and child
If App renders <Header />, App is the parent and Header is the child.
Component tree
All your components arranged by who renders whom, with the top component (usually App) at the root.
Top level
Directly in the file, not inside any function. Components should be declared here.
Hoisting
JavaScript moving function declarations to the top of their scope, so you can use them before the line where they're written.

Step by step

01Start with repeated JSX

Here is a page that shows three team members. The same block of JSX is written three times. If you want to add a border to every card, you must edit three places.

App.jsxwhole filejsx
function App() {
  return (
    <section>
      <div className="member"><img src="asha.svg" alt="" /><p>Team member</p></div>
      <div className="member"><img src="ravi.svg" alt="" /><p>Team member</p></div>
      <div className="member"><img src="meera.svg" alt="" /><p>Team member</p></div>
    </section>
  );
}

02Move the repeated part into a function

Write a function with a capital-letter name and return the repeated JSX from it. That function is a component.

Member.jsxwhole filejsx
function Member() {
  return (
    <div className="member">
      <img src="avatar.svg" alt="" />
      <p>Team member</p>
    </div>
  );
}

03Use it like a tag

Now App writes <Member /> three times. React sees the capital M, calls Member once for each tag, and puts the results in order. Change Member once and all three cards change. (Right now all three are identical; in Topic 2.3 props make each one different.)

App.jsxwhole filejsx
function App() {
  return (
    <section>
      <h1>Our team</h1>
      <Member />
      <Member />
      <Member />
    </section>
  );
}
Use it like a tagdiagram
Rendering diagram…

04Know what a component may return

A component returns one thing: an element, a Fragment, text, a number, an array of keyed elements, or null for nothing. true, false and undefined also show nothing. Objects (like { name: "Asha" }) and functions can't be shown and make React complain.

05Keep every component at the top level

Declare components side by side in the file, not nested inside each other. A component written inside another one is re-created on every render, and React treats each new copy as a different component, wiping its state. The live example below shows it happen.

App.jsxwhole filejsx
// Good: both at the top level
function Member() { /* ... */ }
function App() { return <Member />; }

// Bad: Member is re-created every time App renders
function App() {
  function Member() { /* ... */ }
  return <Member />;
}

Try it yourself

  1. 1

    Add a fourth planet and a new component

    In "Define once, use many times", add a fourth <Planet />. Then write a new component Moon that returns a small grey circle and render it after the planets. Predict: where in the tree does Moon sit?

  2. 2

    Make the missing return visible

    In "What a component can return", add return in front of <p>I am never shown</p> in Forgot. Predict the new HTML in the console before you look.

  3. 3

    Fix the nested component

    In the last example, cut InnerCounter out of App and paste it above App, at the top level. Click both counters and switch the theme. Predict the second log line first. (Both now stay at 1.)

Code & diagrams

Define once, use many times New tab

`Planet` is written once and rendered three times. `SolarSystem` is the parent, each `Planet` is a child. Change the circle's colour in `Planet` and all three change.

Preview

Press Run to see the page.

Console

Nothing logged yet.
What a component can return New tab

The console prints the real HTML React produced. `Nothing` and `Forgot` left no trace at all: no element, no comment, no error. A missing `return` fails silently.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

<div>Plain text works<ul><li>First</li><li>Second</li></ul></div>
A component defined inside another loses its state New tab

Both counters were at 1. Switching the theme re-rendered `App`, which created a new `InnerCounter` function, so React threw the old one away and its count went back to 0. `Counter`, declared at the top level, kept its count. (`useState` is covered in Topic 4.2.)

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

After two clicks: outer: 1 | inner: 1
After theme switch: outer: 1 | inner: 0

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Put the component in braces instead of a tag

In "Define once, use many times", replace one <Planet /> with {Planet}.

terminal
$ Console
── what you'll see ──
Functions are not valid as a React child. This may happen if you return Planet instead of <Planet /> from render. Or maybe you meant to call this function rather than return it.
<div>{Planet}</div>

Break #2

Nest a component and lose your typing

Define a SearchBox component that returns <input /> inside App, and give App any state that changes (like the theme button above). Type in the box, then click the button.

terminal
$ Preview
── what you'll see ──
The text you typed disappears and the input loses focus every time App re-renders.

Myth vs fact

Myth

Components must be classes.

Fact

Modern React uses function components for everything. Class components still work and appear in old code (Topic 26.4), but new code doesn't need them.

Myth

A component must return a div.

Fact

It can return any element, a Fragment, text, a number, an array of keyed elements, or null. Wrapping everything in divs only adds noise to the DOM.

Myth

Defining a helper component inside the parent keeps it private and tidy.

Fact

It re-creates the component on every render and resets its state. Keep it at the top level of the same file and simply don't export it: that keeps it private too (Topic 2.2).

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    React decides whether to keep or replace a subtree by comparing the element type at each position. Types are compared by reference (===), which is exactly why a component defined inside another breaks: each render produces a new function, so the type never matches (Topic 6.4 covers state and position in depth).

  • ▸

    Don't call components as plain functions ({Planet()}). It "works" for simple cases, but React no longer sees a component at that spot: the child's hooks become part of the parent, so its state is mixed into the parent's, and rules like keys and boundaries stop applying. Always render with JSX.

  • ▸

    Components are expected to be pure (Topic 2.6), and to be cheap to call, because React may call them often: on every parent render, twice in StrictMode, and, with concurrent rendering, possibly more than once before committing.

  • ▸

    The displayName React DevTools shows comes from the function's name. Anonymous default exports (export default () => ...) show up as Anonymous in DevTools and error messages, which is one more reason to name your components.

Remember this

  1. 1

    A function component is an ordinary JavaScript function that returns JSX (the HTML-like syntax from Phase 1). React calls the function and puts what it returns on the screen. You can write it as a function declaration, function Avatar() { return <img ... />; }, or as an arrow function stored in a constant, const Avatar = () => <img ... />;. Both work the same. Most React code uses declarations for components because they read clearly and can be used before the line they're written on (this is called hoisting).

  2. 2

    The name must start with a capital letter. JSX uses the first letter to decide what a tag is: <section> (lowercase) means the built-in HTML element, <Section> (capital) means "call my function named Section". Write <avatar /> and React creates an unknown HTML element called avatar and never calls your function. Use PascalCase for component names: every word starts with a capital, as in ProductCard or TodoListItem.

  3. 3

    A component returns what should appear. That can be one JSX element (with anything inside it), a Fragment <>…</> holding several elements, a string or number (shown as text), an array of elements with keys, or null to show nothing. If you forget the return inside braces, the function returns undefined and React shows nothing, with no error. That silent blank is a classic beginner bug.

  4. 4

    Using a component is called rendering it or creating an instance of it. Each <Avatar /> you write is a separate instance: React calls your function once for each one, and each instance keeps its own memory (its state, Phase 4). Components can render other components, which builds the component tree you met in Topic 0.2. The component that renders another is its parent; the one being rendered is the child.

  5. 5

    Never define a component inside another component. If you write function Child() inside the body of function Parent(), a brand-new Child function is created every time Parent renders. React compares components by identity: a new function is a *different type* of component, so React throws away the old Child, its DOM and its state, and builds a fresh one. Typing disappears, focus is lost, and it's slower. Always declare components at the top level of the file and pass any data they need as props (Topic 2.3).

  6. 6

    Components keep big UIs manageable. Each one has one job, a name that says what it is, and can be reused, tested and changed on its own. A good rule of thumb: if you copy the same chunk of JSX a second time, or a chunk has an obvious name ("the header", "one comment"), make it a component.

Explain it without notes

01

What is a function component, and what rules must its name follow?

02

What can a component return? What happens if it returns undefined?

03

Why should you never define a component inside another component?

04

What is the difference between <Planet />, {Planet} and {Planet()} in JSX?

Practice

01

Write a Logo component that returns an <h1> with the text Hectal and use it twice inside App.

02

This code shows nothing. Find and fix the bug: ``jsx function Welcome() { <h2>Welcome!</h2>; }

03

Turn this into two components, Header and App, so the header markup lives in its own component: ``jsx function App() { return ( <main> <header><h1>Recipes</h1><p>Cook something new</p></header> <p>Pick a recipe below.</p> </main> ); }

Trade-offs

  • ↔

    Small components are easier to read, test and reuse, but splitting too finely (a component per <span>) makes code harder to follow. Split when a piece has a clear name and job, or when it repeats.

  • ↔

    Declaration (function Card() {}) versus arrow (const Card = () => ...): no difference to React. Declarations are hoisted and always named; arrows need the const before use. Pick one style per project and stick to it.

Done when you can

  • I can write a function component and render it as a tag.

  • I know why component names start with a capital letter.

  • I can list what a component may return, and spot a missing return.

  • I can explain why components must be declared at the top level.

  • I can tell <Card /> from {Card} and {Card()}.