The First Function Component
Right now our App.jsx has just one JavaScript function in it, and I want to keep it this small for a bit. Because if we immediately start throwing state, props, events and ten different components into this file, you'll know how to write React code, sure, but maybe not what React is actually doing with that code.
So for now, this is all we've got:
export default function App() {
return <h1>My first React screen</h1>;
}And yep, that's a React component.
But look at the code itself for a second. There is no ReactComponent class here, no registration call, no new Component() or anything of that sort. It's just a JavaScript function. React treats this function as a component when you use it as a React element type during rendering.
React sees an <App />, calls the App function, gets some React content back, and then continues rendering whatever that function returned.
That's pretty much the contract.
Read it as normal JavaScript first
Forget about export default for a minute and just look at this:
function App() {
return <h1>My first React screen</h1>;
}There's nothing React-specific about the function declaration itself. function declares a function, App is its name, the parentheses are where parameters would go, and the function body returns some value back to whoever called it.
That returned value happens to be JSX.
And as we already saw earlier, JSX produces React element values. So when React calls App(), it gets back a description saying, roughly, "there should be an h1 here with this text inside it."
React renders an App element
-> React calls App
-> App returns React content
-> React continues rendering that contentOne small thing which is easy to miss: declaring the function does not run it. JavaScript reads the declaration and creates the function, that's all.
function App() {
console.log("App rendered");
return <h1>My first React screen</h1>;
}That log doesn't print just because this code exists in the file. It prints when React actually calls App during rendering.
Defining a component and rendering a component are two different events. The function can exist in memory without React having called it even once.
Use the component through JSX
Back in main.jsx, we had something like this:
root.render(<App />);So what exactly is <App /> doing?
That JSX creates a React element whose type points to the App function. React sees that function type while rendering and then calls it.
You might now ask, okay, if App is just a function anyway, why can't I simply do this?
root.render(App());And annoyingly, with this tiny component, that can appear to work.
You may still get the exact same heading in the browser.
But you've skipped an important part: React is no longer the one calling App as a component. You're calling it yourself as a normal JavaScript function and handing React whatever value came back.
That causes problems once components start using Hooks, and it also breaks React's normal handling of component identity, component stacks, development checks and other render behavior. React expects component calls to come from React.
So this:
root.render(<App />);is the normal way.
This:
root.render(App());is not how you render a component.
Use React components as React elements, normally through JSX. Don't manually call component functions because you want their UI output.
Normal helper functions are completely fine to call yourself though.
function formatTitle(title) {
return title.toUpperCase();
}And then:
function App() {
const title = formatTitle("ReactBook");
return <h1>{title}</h1>;
}formatTitle() is just a JavaScript helper. React doesn't need to manage that function call. It takes a string, returns another string, done.
App is different because React is using it as part of the component tree.
Why component names start with a capital letter
You've probably already noticed that React component names always seem to start with uppercase letters.
<App />
<main />That capital A is actually doing something.
When JSX sees <App />, it treats App as a JavaScript binding. So it looks for a variable or function called App, finds your function, and uses that function as the element type.
When JSX sees <main />, the name starts lowercase, so it treats "main" as a host element name. In a browser React app, React DOM eventually creates a real <main> element from that.
And yeah, getting the capitalization wrong can make your function sit there doing absolutely nothing.
function app() {
return <h1>ReactBook</h1>;
}
root.render(<app />);You might look at this and think React should call app().
It won't.
Because <app /> starts lowercase, JSX treats it as an element named app, same way it treats div, main, or button. Your JavaScript function called app isn't referenced by that JSX at all.
Change the function name:
function App() {
return <h1>ReactBook</h1>;
}And use:
<App />Now JSX refers to your function.
So component bindings need to start uppercase. This is part of how JSX tells your own components apart from host elements.
Definition, element, and instance
There are three terms I want to separate here because later on we're going to use all of them, and if we use them to mean the same thing, state discussions get confusing very fast.
Take this function:
function LessonCard() {
return <article>JSX Produces Elements</article>;
}This function is the component definition. It's the reusable JavaScript code we wrote.
Then this:
<LessonCard />is a React element using that component type.
Now suppose we write:
function App() {
return (
<main>
<LessonCard />
<LessonCard />
</main>
);
}We still have only one LessonCard function definition. We wrote that function once. But we're rendering it in two positions, so React has two separate rendered occurrences of that component in the tree.
We'll call those component instances when we need to talk about them separately.
This becomes much easier to see once state comes into the picture. Imagine both LessonCard instances have their own local counter. They both execute the same LessonCard function code, but one can have a count of 2 while the other has a count of 7.
Same function definition. Separate places in the React tree. Separate local state.
Writing a component function once does not mean React only gets one copy of its state. Each rendered position can have its own component instance and its own local state.
And none of these component names become HTML tags, by the way.
If LessonCard returns:
<article>JSX Produces Elements</article>the browser DOM contains an article.
You won't find:
<LessonCard>inside the browser Elements panel because LessonCard belongs to your React component tree, not the HTML DOM.
Components can render other components
Let's make another function:
function ChapterHeading() {
return <h1>The First React Screen</h1>;
}And now use it inside App:
function App() {
return (
<main>
<ChapterHeading />
<p>Six lessons</p>
</main>
);
}What happens when React renders <App /> now?
React calls App. App returns some React content containing a <main>, a <ChapterHeading />, and a <p>.
While React continues through that returned tree, it reaches <ChapterHeading />. That's another component type, so React calls ChapterHeading as well. That function returns an h1, and React continues from there.
So the React component side looks something like:
App
ChapterHeading
h1
pDon't read this as actual HTML nesting though. The browser isn't creating an <App> node and then putting a <ChapterHeading> node inside it.
App and ChapterHeading are function components. Their lowercase output eventually becomes browser elements.
When should you make another component?
Now comes a question people ask a lot when they're new to React: how much stuff should I pull into separate components?
And there's no magic line count for this.
My own rule is pretty simple. If extracting something gives that piece of UI a useful name or a useful job, then yeah, making a component can make sense.
For example:
function ChapterHeading() {
return <h1>The First React Screen</h1>;
}ChapterHeading tells me what that piece of UI represents. If I see this inside App, I already know what section I'm looking at without reading the h1 contents.
But this:
function Paragraph() {
return <p>Six lessons</p>;
}doesn't really tell me anything useful.
I replaced a p with a function called Paragraph, which is just another way of saying p with more code around it.
Components become useful when they represent some meaningful UI section, repeat with different inputs, contain behavior, own some state, or help a parent component stay readable without hiding everything behind random names.
Making a component for every HTML element just gives you a lot more functions to jump through.
Pull something into a component when that function gives the UI a useful React-level name or job. Don't extract stuff just because JSX allows you to.
Naming components
Since component names appear everywhere in React code, spending five seconds on a decent name saves you annoyance later.
Take this:
function LessonProgress() {
return <p>0 of 6 lessons complete</p>;
}LessonProgress is pretty clear. If that name appears in React DevTools, an error component stack, an import, or a search result six months later, you already have some idea what you're looking at.
Now compare that with:
Wrapper
Wrapper2
ContentThing
Component1Yeah, good luck.
Use PascalCase for component names:
App
ChapterHeading
LessonProgress
ContinueButtonAnd don't make the name longer just for the sake of sounding formal. Something such as AppChapterHeadingComponent is usually worse than ChapterHeading. We already know it's a component because we're looking at React code and it's capitalized.
Give it the shortest name that still tells you what UI job it has.
Component rendering should stay pure
Now we're getting to one of the more important rules about component functions.
When React calls your component, that call should calculate UI from the values available for that render. The component body shouldn't be changing random external values while that calculation is happening.
For example, don't do this:
let renderCount = 0;
function App() {
renderCount += 1;
return <p>Render {renderCount}</p>;
}This looks innocent enough, but now every time React happens to call App, you're modifying a variable outside the component.
And how many times will React call App?
Maybe once for an update. Maybe more than once while working in development. Some render work may even be started and then abandoned before anything gets committed to the DOM.
So using "number of function calls" as application state is already broken.
In development Strict Mode, React deliberately calls some render logic extra times to help expose code that behaves differently when repeated. With code like the example above, you'll immediately start seeing values you didn't expect.
Instead, calculate output from actual inputs:
function LessonProgress({ completed }) {
return <p>{completed} lessons complete</p>;
}If completed is 3, this render calculates text for 3 lessons complete. The component didn't change some outside variable while doing that.
And local calculations inside the function are completely fine:
function ChapterHeading() {
const title = "The First React Screen";
const label = title.toUpperCase();
return <h1>{label}</h1>;
}We're creating title and label during this call, using them to calculate some JSX, and then that call ends. We're not changing shared external data.
One thing about console.log(): you'll absolutely use it while debugging components, I do too. Just remember that a render log can appear more times than you expected because React can render more times than the browser visibly updates.
So never build application behavior around a render log happening once.
Don't define components inside components
You technically can write this:
function App() {
function ChapterHeading() {
return <h1>The First React Screen</h1>;
}
return <ChapterHeading />;
}JavaScript allows it. React isn't going to stop the file from compiling.
But don't define components this way.
Every time App runs, JavaScript creates a new ChapterHeading function object. On the next render, React gets another new function object. As far as component type identity goes, that's a different type from the previous function object.
That means React can treat the previous component as gone and the new one as a new component. If the nested component had local state, that state can get reset because you're giving React a new component type each time the parent renders.
Put component definitions at module level instead:
function ChapterHeading() {
return <h1>The First React Screen</h1>;
}
function App() {
return <ChapterHeading />;
}Now ChapterHeading refers to the same function object across App renders.
It's also easier to read. You can scan the file and see the components declared next to each other instead of finding function definitions hidden inside other function bodies.
Exporting App
Our main.jsx needs to import App, so App.jsx has to export it somehow.
Right now we're using a default export:
export default function App() {
return <h1>My first React screen</h1>;
}Then main.jsx can import it:
import App from "./App.jsx";Because it's a default export, the importing file technically gets to choose its own local name. It could write:
import Whatever from "./App.jsx";and that would still import the default export.
Please don't do that for no reason, obviously.
For this project, keep the generated App default export as it is. main.jsx already expects that file to provide the root component.
Let's make our first small component tree
Okay, now we can finally change App.jsx a little.
Add these two component definitions at module level:
function ChapterHeading() {
return <h1>The First React Screen</h1>;
}
function LessonProgress() {
return <p>0 of 6 lessons complete</p>;
}Then use them inside App:
export default function App() {
return (
<main>
<ChapterHeading />
<LessonProgress />
</main>
);
}Save the file and look at the browser.
You'll see a heading and a paragraph inside main, exactly as expected.
Now open React DevTools and the tree looks different from what the browser Elements panel shows. React DevTools can show App, ChapterHeading, and LessonProgress because those are part of the React component tree.
The browser Elements panel only shows the DOM output:
<main>
<h1>The First React Screen</h1>
<p>0 of 6 lessons complete</p>
</main>And this is a good point to stop and make sure those two trees don't get mixed together in your head.
React rendered <App />, so React called App. App returned JSX containing <ChapterHeading /> and <LessonProgress />, so React called those functions too. Those functions returned lowercase host elements, and React DOM created the corresponding DOM nodes.
No one manually called:
App();
ChapterHeading();
LessonProgress();React handled those component calls because the functions appeared as element types in the React tree.
Check if you've got the terminology
Take ChapterHeading from the example.
This:
function ChapterHeading() {
return <h1>The First React Screen</h1>;
}is the component definition.
This:
<ChapterHeading />is a React element using that component type.
When React reaches that element during rendering, React calls the ChapterHeading function.
And this:
<h1>The First React Screen</h1>is the browser DOM output produced from what the component returned.
If you put <ChapterHeading /> in two different places, you still wrote one component function, but React can now have two separate instances of that component in its tree.
That's the part I want you to leave this lesson with.
A function component really is a JavaScript function. React isn't changing the JavaScript function syntax or secretly turning it into some other language construct. What makes the function participate in React is how React uses it during rendering.
You write <ChapterHeading />, React sees your function as the element type, React calls it, and whatever React content comes back becomes the next part of the tree to process.
And once state arrives in the next few lessons, that little difference between "the function I wrote" and "this particular rendered instance of that function" is going to become very useful.