API reference
raf-effect-atom/rsc
Connects the loader verbs to React Server Components, such as the Next.js App Router.
Server components share one request registry per request through React's
cache: they start atoms with prefetch, ensure and fetch, pass the
handles those return to client components as props, and render them under
<HydrationBoundary registry={getRegistry()}> from raf-effect-atom,
which hydrates the registry of the root's RegistryProvider.
makeRequestAtoms makes the same functions over a request registry that a
seed prepares, such as with the request's cookie.
import {
makeRequestAtoms,
getRegistry,
prefetch,
prefetchInBrowser,
ensure,
fetch,
run,
} from "raf-effect-atom/rsc";RequestAtoms
interface RequestAtoms extends Loader.Loader {
/**
* The request registry of the server render in progress, for
* `HydrationBoundary`'s `registry`.
*/
readonly getRegistry: () => AtomRegistry.AtomRegistry;
}The loader verbs over the request registry of the server render in progress, with its registry.
makeRequestAtoms
const makeRequestAtoms: (
options?: RequestRegistry.Options,
) => RequestAtoms;Creates the verbs and getRegistry over a request registry that seed
prepares.
When to use
Use when the request's atoms need something from the request before they
run, such as an RPC protocol that forwards the page request's cookie. Make
them once, in a server-only module, and call the verbs on them instead of
the ones raf-effect-atom/rsc exports.
Details
The seed runs on each request's registry when a server component first
uses it. It can be async, as headers() is: ensure and fetch wait
for it, prefetch returns its handle at once and starts the atom once the
seed resolves, and HydrationBoundary waits for both.
Example
// src/atoms.server.ts
import "server-only"
import { headers } from "next/headers"
import { makeRequestAtoms } from "raf-effect-atom/rsc"
export const atoms = makeRequestAtoms({
seed: async (registry) => {
registry.set(requestCookie, (await headers()).get("cookie") ?? undefined)
}
})getRegistry
const getRegistry: () => AtomRegistry.AtomRegistry;Returns the request registry of the server render in progress.
Details
Made once per request through React's cache, and disposed through
cacheSignal when React finishes the render, after the last streamed
result has been sent. The verbs take the same signal: when React aborts
the render, such as for a navigation the browser left, the ensure and
fetch calls still waiting reject with its reason.
Gotchas
Only server components share it: outside a server component render,
cache doesn't cache, so each call makes a new registry.
prefetch
const prefetch: <S extends Source>(
source: S,
...args: ArgsOf<S>
) => Handle<S>;Loader.prefetch on the request's registry: starts a source's atom, to
stream it, and returns its handle.
prefetchInBrowser
const prefetchInBrowser: <S extends Source>(
source: S,
...args: ArgsOf<S>
) => Handle<S>;Loader.prefetchInBrowser on the request's registry: returns a handle
whose atom the browser's read starts, without starting it on the server.
ensure
const ensure: <S extends Source>(
source: S,
...args: ArgsOf<S>
) => Promise<LoadedHandle<S>>;Loader.ensure on the request's registry: starts a source's atom, waits
for its result, and returns its handle.
fetch
const fetch: <S extends Source>(
source: S,
...args: ArgsOf<S>
) => Promise<LoadedHandle<S>>;Loader.fetch on the request's registry: starts or refreshes a source's
atom, waits for the new result, and returns its handle.
run
const run: Loader.Loader["run"];Loader.Loader's run on the request's registry: runs an Effect that
needs the registry, such as the Effect verbs in an Effect.gen.
Example
const handles = await run(
Effect.gen(function* () {
const issueHandle = yield* Loader.ensure(issue, id)
return { comments: yield* Loader.prefetch(commentPage, id, 0), issue: issueHandle }
})
)