Server Components & React 19
Roughly 15% of a typical loop — and 15% of the mock exam here.
Server Components are the highest-signal React 19 topic in current loops: most candidates met them through a framework’s folder conventions, and interviewers probe whether you know the actual model underneath.
Server vs client components
Server components render ahead of time — at build time or per request — in an environment separate from the browser. Their code never ships in the bundle; only their rendered output does.
- Server components can be
async, read a database or the filesystem directly, and hold secrets. They cannot useuseState,useEffect, event handlers, or browser APIs — the component itself never reaches the client, so nothing interactive survives. - Client components own interactivity. They still server-render to HTML and then hydrate — “client” describes where the code becomes interactive, not the only place it runs.
- Trap answer: “RSC replaces SSR.” False. SSR turns client components into first-paint HTML; RSC is a separate layer of components that never hydrate at all; the two compose.
Directives mark boundaries, not files
The rule that resolves most directive confusion: 'use client' and 'use server' are boundary markers on the module graph, not per-file execution labels.
'use client'at the top of a file marks where the import graph crosses from server to client. Everything that file imports becomes client code transitively — no further directives needed.- Most components carry no directive at all; the same component definition can render as server or client depending on which side of a boundary imports it.
'use server'does not mark a server component — it marks Server Functions, server-side functions callable from the client. There is no directive for server components; that is the trap.- The boundary follows imports, not the render tree: a client component can still render server-rendered children it receives via props.
The serialization boundary
Props crossing from server to client travel in a serialized payload, so they must be serializable: primitives, plain objects and arrays, Map, Set, Date, FormData, JSX, Promises, and Server Functions. Regular functions, classes, and class instances do not cross.
- The classic failure: passing
onClickfrom a server component into a client component. Fix: define the handler inside the client component, or pass a Server Function. - Promises are legal props — start fetching on the server, pass the promise down, and read it in the client with
use(promise), which suspends until it resolves. Unlike a hook,usemay be called conditionally, but it does not support promises created during render.
Actions and the React 19 hooks
React 19 made async mutations first-class. A <form> now accepts a function as its action, and React wraps the submission in a transition automatically, managing pending state, errors, and optimistic updates.
const [state, submitAction, isPending] = useActionState(
async (prevState, formData) => save(formData.get('name')),
null,
);
useActionStatereturns the latest result, an action to hand a form, andisPending. The callback receives previous state first, then the payload. With Server Functions it can respond before hydration completes — progressive enhancement for free.useOptimisticshows the expected value while an action is pending and reverts automatically if it fails.- Terminology check: a Server Function called inside an action is a Server Action. Always treat its arguments as untrusted input and authorize every mutation on the server.
React 19 changes and rendering models
refis a regular prop on function components;forwardRefis deprecated, with a codemod. Ref callbacks may return cleanup functions, and<Context>renders directly as a provider.- SSG renders HTML once at build, SSR renders per request, and streaming sends HTML in chunks as Suspense boundaries resolve. RSC composes with all three rather than replacing any of them.
- The precise bundle-size claim: RSC shrinks the bundle only for code that stays server-only. A markdown renderer used in a server component ships zero client JS; put
'use client'at the root and the benefit disappears.
Sample questions
6 of the 30 questions this domain carries in practice mode — expand one to check yourself before drilling.
1. Which of these is a Server Component unable to do?
- read from a database or the filesystem directly while rendering
- call useState or attach event handlers like onClick to its elements
- render Client Components as part of the tree it returns
- declare its function body async and await data before returning JSX
Answer: B. Server Components run ahead of time and never re-render, so stateful hooks and event handlers belong to Client Components; async bodies and direct data access are fine.
2. The 'use client' directive at the top of a file means:
- the module is a client boundary entry point — it and everything it imports become client code
- the component skips server rendering entirely and only ever executes in the browser
- React inlines the file into the HTML document so the browser can parse it sooner
- the file opts out of Strict Mode double-rendering during development
Answer: A. The directive marks a boundary in the module graph, not per-file behavior — every transitive import of a 'use client' module ships in the client bundle too.
3. A developer marks a component 'use client', then is surprised to find its markup in the server-rendered HTML source. What happened:
- Client Components are still prerendered to HTML during SSR — the directive controls bundling and hydration, not where the initial HTML comes from
- the framework silently ignored the directive because the file contained no event handlers or stateful hooks that would justify creating a client boundary
- the HTML is a stale cached copy from a previous deployment that predates the directive being added to the file
- a parent Server Component inlined the child's output before the directive could take effect at request time
Answer: A. 'use client' does not mean client-only — during SSR the component still runs on the server to produce HTML, then hydrates into an interactive tree in the browser.
4. A utility module imported by a file marked 'use client':
- stays server code unless it declares its own directive
- is duplicated into a shared chunk that neither environment executes
- throws an error at build time unless the module is explicitly listed in the bundler's external packages configuration
- becomes client code too — the directive pulls every transitive import into the client graph
Answer: D. The boundary is drawn in the module graph, so one 'use client' entry point drags its entire import tree — components, helpers, data files — into the browser bundle.
5. During streaming SSR, a slow product panel placed above a fast reviews panel arrives later in the HTML stream, yet both render in the correct positions on screen. How:
- the browser buffers the entire stream and sorts the chunks into DOM order before painting anything
- inline scripts in the stream slot each boundary's HTML into its placeholder, so arrival order need not match document order
- HTTP/2 multiplexing reorders the response frames so the markup always arrives in document order
- the reviews panel's streamed HTML is discarded and fully re-rendered on the client once the slower product panel finally arrives
Answer: B. Streamed Suspense content arrives as hidden markup plus a tiny script that moves it into the fallback's slot — resolution order never blocks earlier pixels.
6. A component early-returns a skeleton before reading a theme context. The lint rule rejects useContext there but accepts use(ThemeContext). Why is use() allowed:
- the linter simply has no rule for use() yet, so the code is equally broken at runtime
- use() defers the actual context read until after the render commits to the DOM, so call order stops mattering
- use(ThemeContext) creates its own provider scope, making hook ordering irrelevant
- use() is exempt from the unconditional-call rule, so reading context after an early return is legal
Answer: D. Conditional context reads are the headline use(Context) feature; it still resolves the nearest provider above the calling component, exactly as useContext does.
Drill this domain in practice mode →
Independent community study resource — not affiliated with or endorsed by Meta Platforms, Inc. React is a trademark of Meta Platforms, Inc. All questions and study notes are original, written from the official React documentation. Everything runs in your browser; nothing you answer is stored or transmitted.