# raf-effect-atom/tanstack-router

> Connects the loader verbs to TanStack Router and TanStack Start.

`getRouter` runs once per request on the server and once in the browser.
It makes the registry with `makeRegistry`, puts `Loader.make(registry)` on
the router context for the loaders, and calls `setupRouterAtoms`, which
provides the registry to the app and sends it from the server to the
browser through the router's own dehydration.

**Example**

```tsx
import { createRouter } from "@tanstack/react-router"
import { Loader } from "raf-effect-atom"
import { makeRegistry, setupRouterAtoms } from "raf-effect-atom/tanstack-router"

export function getRouter() {
  const registry = makeRegistry()
  const router = createRouter({
    routeTree,
    context: { atoms: Loader.make(registry) }
  })
  setupRouterAtoms({ router, registry })
  return router
}
```

```ts
import { makeRegistry, setupRouterAtoms } from "raf-effect-atom/tanstack-router";
```

## `DehydratedRouterAtoms`

<p class="api-meta"><span class="api-kind">interface</span><span>models</span><span>since 0.1.0</span><a href="https://github.com/KATT/raf-effect-atom/blob/main/packages/raf-effect-atom/src/tanstack-router.tsx#L49">Source</a></p>

```ts
interface DehydratedRouterAtoms {
  readonly "raf-effect-atom": ReadonlyArray<EffectHydration.DehydratedAtom>;
}
```

The key `setupRouterAtoms` adds to the router's dehydrated state.

## `RouterAtomsOptions`

<p class="api-meta"><span class="api-kind">interface</span><span>models</span><span>since 0.1.0</span><a href="https://github.com/KATT/raf-effect-atom/blob/main/packages/raf-effect-atom/src/tanstack-router.tsx#L60">Source</a></p>

```ts
interface RouterAtomsOptions<TRouter extends AnyRouter> {
  /** The registry the router context's loader verbs run on. */
  readonly registry: AtomRegistry.AtomRegistry;
  readonly router: TRouter;
}
```

Options for `setupRouterAtoms`.

## `makeRegistry`

<p class="api-meta"><span class="api-kind">const</span><span>constructors</span><span>since 0.1.0</span><a href="https://github.com/KATT/raf-effect-atom/blob/main/packages/raf-effect-atom/src/tanstack-router.tsx#L110">Source</a></p>

```ts
const makeRegistry: (options?: {
  readonly defaultIdleTTL?: number | undefined;
  readonly initialValues?: RequestRegistry.InitialValues | undefined;
  readonly seed?: RequestRegistry.Seed | undefined;
}) => AtomRegistry.AtomRegistry;
```

Creates the registry for one `getRouter` call: a request registry on the
server, and in the browser a registry like `@effect/atom-react`'s
`RegistryProvider` makes.

**Details**

- The server is anywhere without a `window`. To decide otherwise, make
  the registry with `RequestRegistry.make` on the server and
  `AtomRegistry.make` in the browser.
- `defaultIdleTTL` is how many milliseconds the browser's registry keeps
  an atom no component reads, 400 by default, as `@effect/atom-react`'s
  default registry does. An atom's own `Atom.setIdleTTL` or
  `Atom.keepAlive` wins. The server's request registry lives for one
  request, so it has none.
- `initialValues` are values both registries start with, as
  `AtomRegistry.make`'s `initialValues`, such as the session the server
  verified or a readable atom that provides the request's `fetch`. The
  server's request registry keeps those atoms mounted until it's disposed.
  The browser's registry drops an atom no component reads, value included,
  so make one whose value must outlive its readers `Atom.keepAlive`.
- `seed` runs on the server's request registry before the loaders start
  atoms in it, as `RequestRegistry.make`'s does: set what the request's
  atoms need, such as its cookie. It can be async. The browser's registry
  isn't seeded.

**Example**

```ts
import { getRequestHeader } from "@tanstack/react-start/server"
import { makeRegistry } from "raf-effect-atom/tanstack-router"

const registry = makeRegistry({
  // Keeps an issue the user navigated away from for a minute.
  defaultIdleTTL: 60_000,
  // In-process RPC calls send the page request's cookie.
  seed: (registry) => registry.set(requestCookie, getRequestHeader("cookie"))
})
```

## `setupRouterAtoms`

<p class="api-meta"><span class="api-kind">const</span><span>integrations</span><span>since 0.1.0</span><a href="https://github.com/KATT/raf-effect-atom/blob/main/packages/raf-effect-atom/src/tanstack-router.tsx#L146">Source</a></p>

```ts
const setupRouterAtoms: <TRouter extends AnyRouter>(
  options: RouterAtomsOptions<TRouter>,
) => void;
```

Provides a registry to a TanStack router's app and streams it from the
server to the browser.

**Details**

- Wraps the app in `RegistryContext.Provider` through the router's `Wrap`
  option, inside any `Wrap` it has already.
- On the server, adds `Hydration.dehydrate(registry)` to the router's
  dehydrated state once the loaders have run, so results still loading
  cross as promises on the router's stream, and disposes the registry when
  the response finishes.
- In the browser, hydrates the registry from that state before the app
  renders.

**Gotchas**

The server's registry must be a request registry and the browser's must
not, so it throws otherwise: a registry shared between requests would send
one user's results to another. Only atoms in the registry when the loaders
finish are sent; one first read while rendering runs again in the browser.
