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
Apprenders<Header />,Appis the parent andHeaderis 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.
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.
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.)
function App() {
return (
<section>
<h1>Our team</h1>
<Member />
<Member />
<Member />
</section>
);
}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.
// 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
Add a fourth planet and a new component
In "Define once, use many times", add a fourth
<Planet />. Then write a new componentMoonthat returns a small grey circle and render it after the planets. Predict: where in the tree doesMoonsit? - 2
Make the missing return visible
In "What a component can return", add
returnin front of<p>I am never shown</p>inForgot. Predict the new HTML in the console before you look. - 3
Fix the nested component
In the last example, cut
InnerCounterout ofAppand paste it aboveApp, at the top level. Click both counters and switch the theme. Predict the second log line first. (Both now stay at 1.)
Code & diagrams
`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
Console
Nothing logged yet.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
Console
Nothing logged yet.Expected console output
<div>Plain text works<ul><li>First</li><li>Second</li></ul></div>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
Console
Nothing logged yet.Expected console output
After two clicks: outer: 1 | inner: 1
After theme switch: outer: 1 | inner: 0Break 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}.
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.
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
displayNameReact DevTools shows comes from the function's name. Anonymous default exports (export default () => ...) show up asAnonymousin DevTools and error messages, which is one more reason to name your components.
Remember this
- 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
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 namedSection". Write<avatar />and React creates an unknown HTML element calledavatarand never calls your function. Use PascalCase for component names: every word starts with a capital, as inProductCardorTodoListItem. - 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, ornullto show nothing. If you forget thereturninside braces, the function returnsundefinedand React shows nothing, with no error. That silent blank is a classic beginner bug. - 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
Never define a component inside another component. If you write
function Child()inside the body offunction Parent(), a brand-newChildfunction is created every timeParentrenders. React compares components by identity: a new function is a *different type* of component, so React throws away the oldChild, 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
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
What is a function component, and what rules must its name follow?
What can a component return? What happens if it returns undefined?
Why should you never define a component inside another component?
What is the difference between <Planet />, {Planet} and {Planet()} in JSX?
Practice
Write a Logo component that returns an <h1> with the text Hectal and use it twice inside App.
This code shows nothing. Find and fix the bug:
``jsx
function Welcome() {
<h2>Welcome!</h2>;
}
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 theconstbefore 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()}.