Your UI as a tree
See how React models your app as a tree of components, how it differs from the tree of imported files, and how it decides what renders and what state survives.
- 01Draw a render treeRead a component's JSX and draw the tree React renders from it: the root, parents, children, top-level components, and leaves.
- 02Tell the render tree from the module treeSay what a node and an arrow mean in each tree, and why a bundler follows the imports while React follows what renders.
- 03Use the tree to predict renders and statePredict which components render after a state change, and what happens to a component's state when it leaves the tree.
A shop page is a tree of components
By now you can split a page into components and put components inside components. Here is a small tea shop built that way: a header with a search box, a list of products, and a cart summary. Read it from the bottom up, starting at App:
const products = [ { id: 1, name: "Green tea", price: 4 }, { id: 2, name: "Black tea", price: 3 }, { id: 3, name: "Mint tea", price: 5 },]; function SearchBox() { return <input placeholder="Search teas" />;} function Header() { return ( <header> <h1>Tea Corner</h1> <SearchBox /> </header> );} function ProductCard({ name, price }) { return <li>{name}: ${price}</li>;} function ProductList() { return ( <ul> {products.map((product) => ( <ProductCard key={product.id} name={product.name} price={product.price} /> ))} </ul> );} function CartSummary() { return <p>Items in cart: 0</p>;} export default function App() { return ( <> <Header /> <ProductList /> <CartSummary /> </> );}App (lines 38 to 46) renders three components: Header, ProductList, and CartSummary, on lines 41 to 43. Header (lines 11 to 18) renders a heading and, on line 15, a SearchBox. ProductList (lines 24 to 32) uses map on line 27 to render one ProductCard for each of the three products from lines 1 to 5. The result shows the shop name, the search box, three teas with their prices, and Items in cart: 0.
Each component sits inside the one that renders it, and that one inside another, up to App. A shape like that is called a tree: one item at the top, each item with any number of items under it. (You met one in plain JavaScript already: the browser keeps a page as the DOM tree.) React keeps your components as a tree too. Drawn out, the shop looks like this:
App is the root. Each arrow goes from a parent to a component it renders, so ProductCard appears three times: one node for each product. The leaves, at the bottom, render no components.A shop's staff chart has the manager at the top. Below are the team leads, and below each lead, the people on their team. You can read off who reports to whom, and who has nobody under them. Three cashiers do the same job, but they're three boxes on the chart.
- In real life: The manager at the top of the chart
- In React: The root component, App
- In real life: A team lead: someone above, a team below
- In React: A component like ProductList: rendered by App, rendering ProductCards
- In real life: Staff with nobody below them
- In React: Leaf components, like SearchBox and ProductCard
- In real life: Three cashiers with the same job, each a separate person
- In React: Three ProductCard nodes from one function
- In real life: A message from the manager goes to everyone below
- In React: When App renders, everything below it renders
React sees your UI as a tree of components. The render tree has one node for each component rendered, with the root component, App, at the top, and an arrow from each parent to each child it renders. Your files make a second tree, the module dependency tree. The render tree explains what renders, where state lives, and how fast your app is.
The render tree: who renders whom
You can draw a render tree from the code alone. For each component, look at the JSX it returns: every component tag in it (a name with a capital letter, like <SearchBox />) is a child. Tags like <header> and <li> are left out. The words for the parts:
- A node is one component, in one place on the page. The shop's tree has 8.
- The root is the node at the top: the component React renders first. Here it's
App, the root component thatmain.jsxhands to React. - A parent renders a child.
HeaderisSearchBox's parent. - The parts below a node, with all their children, are its subtree.
One function can make many nodes. The shop has one ProductCard function, and three ProductCard nodes: one per product, each with its own props. Press Edit & run on the shop and add a fourth product to the array, { id: 4, name: "Oolong", price: 6 }: a fourth card appears, and the tree has a fourth ProductCard node. Delete line 43, and CartSummary leaves the page and the tree.
Why leave out the HTML tags? React isn't only for web pages. The same components can render to a phone app, where there is no <li>. The tags are the platform's building blocks, so the render tree shows only what React manages for you: your components. (React DevTools draws the same tree in its Components tab, which you met in Setting up a React project.)
Top-level and leaf components
Two kinds of node are worth naming. Top-level components sit near the root, like App and ProductList. They often hold the most logic and the most data. Leaf components sit at the bottom and render no components: SearchBox, each ProductCard, and CartSummary. They're usually small, and they're the parts users click and type in most.
The difference matters when something changes. Here is the shop with state in three places: App keeps the cart count, each ProductCard keeps whether it's saved, and SearchBox keeps what you type:
import { useState } from "react"; const products = [ { id: 1, name: "Green tea", price: 4 }, { id: 2, name: "Black tea", price: 3 }, { id: 3, name: "Mint tea", price: 5 },]; function SearchBox() { const [query, setQuery] = useState(""); return ( <input placeholder="Search teas" value={query} onChange={(event) => setQuery(event.target.value)} /> );} function Header() { return ( <header> <h1>Tea Corner</h1> <SearchBox /> </header> );} function ProductCard({ name, price, onAdd }) { const [saved, setSaved] = useState(false); return ( <li> {name}: ${price}{" "} <button onClick={onAdd}>Add</button> <button onClick={() => setSaved(!saved)}>{saved ? "Saved" : "Save"}</button> </li> );} function ProductList({ onAdd }) { return ( <ul> {products.map((product) => ( <ProductCard key={product.id} name={product.name} price={product.price} onAdd={onAdd} /> ))} </ul> );} function CartSummary({ count }) { return <p>Items in cart: {count}</p>;} export default function App() { const [count, setCount] = useState(0); return ( <> <Header /> <ProductList onAdd={() => setCount(count + 1)} /> <CartSummary count={count} /> </> );}Line 10 gives SearchBox its own state for the search text. Line 30 gives each ProductCard a saved flag, and the button on line 35 flips it. Line 55 keeps the cart count in App, which passes a function down through ProductList to each card's Add button (line 59 and line 44), and passes the count to CartSummary on line 60. Click Add on any card and the count goes up.
Which components render after each click? When a component's state changes, React renders that component again, and then every component below it, its whole subtree. Try it in the playground: the shop runs here, and the tree beside it outlines every component that rendered for your last change.
click and typeTea Corner
- Green tea: $4
- Black tea: $3
- Mint tea: $5
Items in cart: 0
first renderApprenders: 0Headerrenders: 0SearchBoxleaf · renders: 0ProductListrenders: 0ProductCard (Green tea)leaf · renders: 0ProductCard (Black tea)leaf · renders: 0ProductCard (Mint tea)leaf · renders: 0CartSummaryleaf · renders: 0
Use the shop on the left: Add, Save, and the search box.
Click Add on any card, then Save on one card, then type in the search box. The tree outlines every component React rendered for your last change.
Add changes App's state, so all 8 components render, even Header and SearchBox, whose props didn't change. Save changes one card's state; it's a leaf, so only that card renders. Typing in the search box renders only SearchBox, once per key you press. That's why leaves render often but cheaply, and why a top-level component with changing state makes a lot of the tree render.
App's state changed, so React renders App and every component below it, all 8. Right: one ProductCard's state changed, and it's a leaf, so only it renders.Rendering everything below is normal, and usually fast: React then changes only the parts of the page that differ. When it does get slow, the tree tells you where to look. memo, useMemo and useCallback and The React Compiler show how to skip a part of the tree whose inputs didn't change.
The tree can change between renders
A render tree is a picture of one render. When a component shows different children in different cases, the tree changes from one render to the next. This cart panel can be hidden. Type a gift note, click Hide cart, then Show cart:
import { useState } from "react"; function CartPanel() { const [note, setNote] = useState(""); return ( <section> <h2>Your cart</h2> <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} /> <p>Note: {note || "none"}</p> </section> );} export default function App() { const [open, setOpen] = useState(true); return ( <> <button onClick={() => setOpen(!open)}> {open ? "Hide cart" : "Show cart"} </button> {open && <CartPanel />} </> );}CartPanel (lines 3 to 16) keeps the note in its own state on line 4, and line 13 shows it. App keeps open on line 19, the button on lines 22 to 24 flips it, and line 25 renders CartPanel only while open is true (&& shows nothing when its left side is false; the Conditional rendering lesson covers it). After you show the cart again, the line says Note: none. Your note is gone.
open is true, CartPanel is in the tree and keeps its note. Right: after Hide cart, it's gone from the tree, and React throws its state away. Showing it again makes a new CartPanel with an empty note.State belongs to a node of the tree. When CartPanel left the tree, React removed it with everything it kept, including the note. Show cart made a brand-new CartPanel, starting from useState("") again. If the note should survive, it has to live in a node that stays, like App: exercise 6 does that.
The module dependency tree
Real projects don't keep every component in one file. Here is the same shop split the usual way: a file per component, the product data in products.js, and a helper that formats prices in formatPrice.js. Click the tabs to read each file:
import Header from "./Header.jsx";import SearchBox from "./SearchBox.jsx";import ProductList from "./ProductList.jsx";import CartSummary from "./CartSummary.jsx"; export default function App() { return ( <> <Header> <SearchBox /> </Header> <ProductList /> <CartSummary /> </> );}In App.jsx, lines 1 to 4 import four components. One thing changed from the one-file shop: on lines 9 to 11, App puts <SearchBox /> between Header's tags. Whatever you put between a component's tags reaches it as a prop called children, and in Header.jsx, line 5 shows it inside the <header>. (The Passing props to a component lesson covers children.) In ProductList.jsx, lines 1 and 2 import ProductCard and the product list. In ProductCard.jsx, line 1 imports formatPrice, and the prices now show as $4.00.
The files and their import lines make a second tree, the module dependency tree. Each node is a file (a module), and each arrow is an import. Its root is the entry file, the one the page loads first: here main.jsx, which every live example has (Pop out shows it) and which imports App.jsx.
import, from the file that has it. The tree holds files, including products.js and formatPrice.js, which hold no components. SearchBox.jsx hangs under App.jsx, which imports it, while in the render tree SearchBox sits under Header, which renders it.Each row asks the same question of both trees:
| Question | The render tree | The module dependency tree |
|---|---|---|
| What is a node? | A component, once for each place it's rendered. | A file: a module. |
| What does an arrow mean? | This component renders that one. | This file imports that one. |
| What's at the top? | The root component, App. | The entry file, main.jsx. |
| Does it change while the app runs? | Yes. Conditions and lists can add and remove nodes on any render. | No. It's fixed by the import lines in your code. |
| What is it good for? | Seeing which components render, and where state lives. | Seeing what goes in the bundle, and why it's big. |
What is the module tree for? Building your app. Before your users get it, a bundler (a tool like the one npm run build runs in the Vite project from Setting up a React project) starts at the entry file, follows every import, and packs the files it reaches into a few files for the browser: the bundle. A file that no import reaches is left out. Try it: OldBanner.jsx sits in the same folder, but nothing imports it yet.
App.jsx, ProductCard.jsxApp.jsx
import Header from "./Header.jsx"; import SearchBox from "./SearchBox.jsx"; import ProductList from "./ProductList.jsx"; import CartSummary from "./CartSummary.jsx";
ProductCard.jsx
import { formatPrice } from "./formatPrice.js";1 left outmain.jsxApp.jsxHeader.jsxSearchBox.jsxProductList.jsxProductCard.jsxformatPrice.js
products.js
CartSummary.jsx
Left out of the bundle: OldBanner.jsx
From main.jsx, the imports reach 9 files, and those go in the bundle. Left out: OldBanner.jsx, because no import reaches it.
Turn on App uses OldBanner: one import line, and OldBanner.jsx joins the tree under App.jsx. Turn off ProductCard uses formatPrice, and formatPrice.js leaves it. Every import pulls a file, and everything that file imports, into the bundle. A big library imported by one small component makes every visitor download it, which is why a slow first load often starts with a look at the module tree. (Loading part of the bundle only when it's needed is dynamic import, and React builds on it with lazy in the Suspense lesson.)
Where the tree comes back later
Much of the rest of this course is about the render tree, even when it doesn't say so. How to read the table: each row is an idea you'll meet, what the tree has to do with it, and the part of the course that teaches it.
| Idea | What the tree has to do with it | Where you learn it |
|---|---|---|
| State | State belongs to one node in the tree, and lives as long as that node stays in it. | Adding interactivity: State: a component's memory |
| Re-renders | A state change renders that component and everything below it. | Adding interactivity: Render and commit |
| Sharing state | Two components share state by keeping it in their closest common parent. | Managing state: Sharing state between components |
| Keeping or resetting state | React keeps state while the same component stays at the same place in the tree. | Managing state: Preserving and resetting state |
| Context | A value passed through context reaches every component below the one that provides it. | Managing state: Passing data deeply with context |
| Skipping renders | memo and the React Compiler skip a part of the tree whose inputs didn't change. | Performance: memo, useMemo and useCallback, and The React Compiler |
| Loading and errors | Suspense and error boundaries wrap a part of the tree and show a fallback for it. | Async and concurrency: Suspense, and Error boundaries |
| Fiber | React keeps its own tree of objects, called fibers: one for each component, and one for each HTML element too. | Under the hood: Fiber: React's unit of work |
The stages, in course order:
- Adding interactivity: state, and the render and commit that follow a change.
- Managing state: choosing which node keeps each piece of state, sharing it through a parent, keeping or resetting it, and context.
- Async and concurrency: Suspense and error boundaries around parts of the tree.
- Performance: when React renders, and how to skip parts of the tree.
- Under the hood: the fiber tree, React's own copy of the tree, with a node for every component and every HTML element, in Fiber: React's unit of work.
Reading the tree of a chat page
A support chat has a sidebar of conversations and a window with the open one. Click Ben and back to Asha. Then type a reply to Asha, and click Ben:
import { useState } from "react"; const conversations = [ { id: 1, name: "Asha", messages: ["Is the green tea back?", "Great, thanks!"] }, { id: 2, name: "Ben", messages: ["Where is my order?"] },]; function ConversationItem({ name, active, onSelect }) { return ( <li> <button onClick={onSelect}>{active ? `> ${name}` : name}</button> </li> );} function Sidebar({ activeId, onSelect }) { return ( <ul> {conversations.map((chat) => ( <ConversationItem key={chat.id} name={chat.name} active={chat.id === activeId} onSelect={() => onSelect(chat.id)} /> ))} </ul> );} function MessageInput() { const [draft, setDraft] = useState(""); return ( <input placeholder="Write a reply" value={draft} onChange={(event) => setDraft(event.target.value)} /> );} function ChatWindow({ chat }) { return ( <section> <h2>{chat.name}</h2> {chat.messages.map((text) => ( <p key={text}>{text}</p> ))} <MessageInput /> </section> );} export default function App() { const [activeId, setActiveId] = useState(1); const chat = conversations.find((item) => item.id === activeId); return ( <> <Sidebar activeId={activeId} onSelect={setActiveId} /> <ChatWindow chat={chat} /> </> );}Read the tree from App down. App (lines 54 to 63) renders Sidebar and ChatWindow. Sidebar renders a ConversationItem for each conversation (lines 19 to 26), and ChatWindow renders MessageInput on line 49. The messages on lines 46 to 48 are <p> tags, so they aren't nodes. The leaves are the two ConversationItems and MessageInput.
The tree tells you where each piece of state lives. Which chat is open is kept in App (line 55), the closest node above both the sidebar, which highlights it, and the window, which shows it. The reply you're typing is kept in the leaf that needs it, MessageInput (line 32), so typing renders only that leaf.
And the reply you typed to Asha is still there after you click Ben. Switching chats gave ChatWindow new props, but MessageInput is the same node, in the same place in the tree, so React kept its state. The Preserving and resetting state lesson explains the rule and the usual fix. For a preview, press Edit & run and change line 60 to <ChatWindow key={chat.id} chat={chat} />: a different key makes React treat each conversation's window as a different node, so the draft starts empty.
- Three ProductCard nodes, one for each product
products.js, a file with data and no componentsmain.jsx, the file at the very topCartPaneldisappearing when the cart is hidden- Which components render after a click on Save
formatPrice.js, a helper functionSearchBoxsitting underHeader, passed in aschildren- What a bundler follows to build your app
Sort each card: is it something you'd see in the render tree, or in the module dependency tree?
Common mix-ups
- "The render tree is the DOM tree." No. The render tree holds your components; the DOM holds the elements they return, like
<li>. React builds the DOM from your components. - "One component, one node." No. A component rendered three times is three nodes, each with its own props and state.
- "The render tree is the same as the import tree." No. One has components and follows what renders; the other has files and follows imports. A component passed as
childrensits in different places in the two. - "The tree is fixed when the page loads." No. Conditions and lists add and remove nodes on any render, and a removed node loses its state.
- "A state change re-renders the whole app." No. It renders the component that changed and its subtree. Above it and beside it, nothing renders.
- "Every file in my project ends up in the bundle." No. The bundler follows imports from the entry file; files nothing imports are left out.
Practice exercises
Draw the tree on paper first: App at the top, then each component tag you find in each component's JSX. Then use the hints, and press Edit & run to change the code and watch the result.
How many components are in this app's render tree?
function MenuItem({ name }) {
return <li>{name}</li>;
}
function Menu() {
return (
<ul>
<MenuItem name="Green tea" />
<MenuItem name="Black tea" />
<MenuItem name="Mint tea" />
<MenuItem name="Lemon cake" />
</ul>
);
}
function Footer() {
return <footer>Open every day</footer>;
}
export default function App() {
return (
<main>
<Menu />
<Footer />
</main>
);
}function MenuItem({ name }) { return <li>{name}</li>;} function Menu() { return ( <ul> <MenuItem name="Green tea" /> <MenuItem name="Black tea" /> <MenuItem name="Mint tea" /> <MenuItem name="Lemon cake" /> </ul> );} function Footer() { return <footer>Open every day</footer>;} export default function App() { return ( <main> <Menu /> <Footer /> </main> );}App, Menu, Footer, and four MenuItems: 7 nodes. <main>, <ul>, <li>, and <footer> are HTML tags, so they aren't in the render tree.
This account bar is the root of its own tree. How many leaf components does it have?
function Avatar({ name }) { return <strong>{name[0]}</strong>;} function UserName({ name }) { return <span>{name}</span>;} function Profile({ name }) { return ( <div> <Avatar name={name} /> <UserName name={name} /> </div> );} function SignOutButton() { return <button>Sign out</button>;} export default function AccountBar() { return ( <nav> <Profile name="Asha" /> <SignOutButton /> </nav> );}function Avatar({ name }) { return <strong>{name[0]}</strong>;} function UserName({ name }) { return <span>{name}</span>;} function Profile({ name }) { return ( <div> <Avatar name={name} /> <UserName name={name} /> </div> );} function SignOutButton() { return <button>Sign out</button>;} export default function AccountBar() { return ( <nav> <Profile name="Asha" /> <SignOutButton /> </nav> );}Avatar, UserName, and SignOutButton render only HTML tags, so they're the 3 leaves. Profile and AccountBar each have component children.
Make a SaleBadge component and have each ProductCard render it when the price is under 4. How many SaleBadge nodes does the tree have then?
const products = [ { id: 1, name: "Green tea", price: 4 }, { id: 2, name: "Black tea", price: 3 }, { id: 3, name: "Mint tea", price: 5 },]; function ProductCard({ name, price }) { return <li>{name}: ${price}</li>;} export default function App() { return ( <ul> {products.map((product) => ( <ProductCard key={product.id} name={product.name} price={product.price} /> ))} </ul> );}const products = [ { id: 1, name: "Green tea", price: 4 }, { id: 2, name: "Black tea", price: 3 }, { id: 3, name: "Mint tea", price: 5 },]; function SaleBadge() { return <strong> Sale</strong>;} function ProductCard({ name, price }) { return ( <li> {name}: ${price} {price < 4 && <SaleBadge />} </li> );} export default function App() { return ( <ul> {products.map((product) => ( <ProductCard key={product.id} name={product.name} price={product.price} /> ))} </ul> );}Only Black tea costs less than $4, so only its ProductCard renders a SaleBadge: 1 node, under that card. The other two cards stay leaves. Change a price to 2 and the tree grows a second badge.
Type Happy birthday as the note, click Hide cart, then Show cart. Predict first: what does the Note line say?
import { useState } from "react"; function CartPanel() { const [note, setNote] = useState(""); return ( <section> <h2>Your cart</h2> <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} /> <p>Note: {note || "none"}</p> </section> );} export default function App() { const [open, setOpen] = useState(true); return ( <> <button onClick={() => setOpen(!open)}> {open ? "Hide cart" : "Show cart"} </button> {open && <CartPanel />} </> );}import { useState } from "react"; function CartPanel() { const [note, setNote] = useState(""); return ( <section> <h2>Your cart</h2> <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} /> <p>Note: {note || "none"}</p> </section> );} export default function App() { const [open, setOpen] = useState(true); return ( <> <button onClick={() => setOpen(!open)}> {open ? "Hide cart" : "Show cart"} </button> {open && <CartPanel />} </> );}Hiding the cart removes CartPanel from the tree, and its note with it. Showing it makes a new CartPanel whose note starts empty, so the line says Note: none.
This app has seven files, in the tabs. A bundler starts at main.jsx. How many files does it leave out of the bundle?
import { createRoot } from "react-dom/client";import App from "./App.jsx"; createRoot(document.getElementById("root")).render(<App />);import { createRoot } from "react-dom/client";import App from "./App.jsx"; createRoot(document.getElementById("root")).render(<App />);The imports reach main.jsx, App.jsx, Menu.jsx, teas.js, and config.js. Nothing imports PriceTag.jsx, so it's left out, and with it formatPrice.js, which only PriceTag.jsx imports: 2 files.
Change the code so the note survives hiding the cart. Type Happy birthday, hide the cart, and show it. What does the Note line say now?
import { useState } from "react"; function CartPanel() { const [note, setNote] = useState(""); return ( <section> <h2>Your cart</h2> <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} /> <p>Note: {note || "none"}</p> </section> );} export default function App() { const [open, setOpen] = useState(true); return ( <> <button onClick={() => setOpen(!open)}> {open ? "Hide cart" : "Show cart"} </button> {open && <CartPanel />} </> );}import { useState } from "react"; function CartPanel({ note, onNoteChange }) { return ( <section> <h2>Your cart</h2> <input placeholder="Gift note" value={note} onChange={(event) => onNoteChange(event.target.value)} /> <p>Note: {note || "none"}</p> </section> );} export default function App() { const [open, setOpen] = useState(true); const [note, setNote] = useState(""); return ( <> <button onClick={() => setOpen(!open)}> {open ? "Hide cart" : "Show cart"} </button> {open && <CartPanel note={note} onNoteChange={setNote} />} </> );}Now App keeps the note, and App never leaves the tree. CartPanel only shows the note and reports changes. Hide and show the cart, and the line still says Note: Happy birthday.
Check your understanding
For each question, draw the tree it's about. Ask whether it's the render tree (components, who renders whom) or the module tree (files, who imports whom).
Question 1 of 7In React's render tree, what is a node?
Choose an answer to see the explanation.
Question 2 of 7How many leaf components does this navigation bar's render tree have?
Read the code, then predictfunction Logo() { return <strong>Tea Corner</strong>; } function NavLink({ label }) { return <a href="#">{label}</a>; } function NavBar() { return ( <nav> <Logo /> <NavLink label="Menu" /> <NavLink label="Cart" /> </nav> ); } export default function App() { return <NavBar />; }Choose an answer to see the explanation.
Question 3 of 7Which tree has
products.js, the file that holds the shop's product list, in it?Choose an answer to see the explanation.
Question 4 of 7In the re-render playground, you click Save on the Black tea card. Which components render?
Choose an answer to see the explanation.
Question 5 of 7You type a gift note, then click Hide cart, so CartPanel leaves the tree. What happens to the note?
Choose an answer to see the explanation.
Question 6 of 7
App.jsximportsSearchBox.jsxand passes<SearchBox />toHeaderas its children. Where is SearchBox in the render tree?Choose an answer to see the explanation.
Question 7 of 7Why do top-level components, near the root, matter most for performance?
Choose an answer to see the explanation.
Key takeaways
- React models your UI as a render tree: one node per rendered component, the root component at the top, arrows from parents to the children they render. HTML tags aren't in it.
- One component can be many nodes, like the three ProductCards, each with its own props and state.
- Top-level components sit near the root; when they render, their whole subtree renders. Leaves render no components, and render often but cheaply.
- The tree can change on every render. A component that leaves it loses its state.
- The module dependency tree has files as nodes and imports as arrows. Bundlers follow it from the entry file, and leave out what nothing imports.
Remember the one-liner.
Components render components: that tree decides what renders and where state lives.
Coming next: Styling components. It compares the main ways to style React components: CSS files, CSS Modules, inline styles, Tailwind, and CSS-in-JS.