Actors, Scripts & APIs: A Gentle Guide to Next.js Components
Picture your frontend as a theater.
The curtain rises. A spotlight sweeps the stage.
Some actors stand still, others dance, and a few call for lines from backstage.
This is the interplay of static, client, and fetcher components in Next.js.
Good web architecture isn’t just about speed—it’s about timing, purpose, and flow.
Static Pages — The Stage is Set
Some parts of your site are like a theater set: built once, ready before the audience arrives.
In Next.js, this is Static Site Generation (SSG). Pages are pre-rendered as HTML and CSS, served instantly, no live data required.
When I built Accessibly Yours at ZafronMoon, pages like /home
, HeroSection.tsx
,
and DemoResults.tsx
were static. They didn’t change unless we redeployed. Like
sturdy stage props, they were reliable and fast.
Use SSG for content that stays the same, like landing pages or marketing sections.
⚡ Client Components — Actors Take the Stage
Some elements need to come alive in real-time.
A button click, a form input, or a smooth scroll—these are the actors of your app.
In Next.js, mark these components with "use client"
to tell the browser: “This
runs interactively.”
For example, in HeroSection.tsx
, a CTA button scrolled users to an audit form.
The component started as static HTML but “hydrated” into a reactive React component
in the browser.
It’s like an actor stepping forward to engage the audience.
Add "use client"
for components using useState
, useEffect
, or browser
APIs like scrollTo
.
🔥 Fetcher Components — Lines from Backstage
Some components don’t just react—they fetch live data from APIs, like actors calling for fresh lines mid-performance.
In Accessibly Yours, components like UrlScanner.tsx
and SiteQualitySnapshot.tsx
pulled audit results from a Lighthouse API or our Fly.io server. These fetchers used
useEffect
or async functions to grab data and update the UI dynamically.
If a component fetches data on load (e.g., useLighthouseScores()
), it’s a
fetcher.
🧩 Why Split /client/
and /fetchers/
?
The distinction isn’t about when the code runs—it’s about what the component does.
Components that need "use client"
:
- Use
useState
oruseRef
- Include button clicks or scroll logic - Call browser APIs likescrollTo
Components that don’t need "use client"
:
- Render static layouts or markup only - Contain pure visual displays (no user input)
- Don’t include interaction or data fetching
Organizing components into /client/
(interactive) and /fetchers/
(data-fetching)
keeps roles clear. At ZafronMoon, this separation reduced bundle sizes and made our
codebase easier to maintain.
🎭 SiteQualitySnapshot — A Supporting Role
Take SiteQualitySnapshot.tsx
.
It receives pre-fetched data as props and displays it. It doesn’t fetch anything itself—it just delivers its lines.
That’s why it lives in /client/
, not /fetchers/
. It’s presentational, not operational,
like an actor reciting a prepared script.
Presentational components belong in /client/
. Fetchers, which handle API
calls, go in /fetchers/
.
🔧 Mind-Map Summary
forms, scrolling) /fetchers → Live data from APIs
This mental model helped us at ZafronMoon build faster, more accessible apps with clear separation of concerns.
When architecture aligns with intention, performance feels like poetry.