Hydrate client state
The server container never crosses the React Server Component boundary. Transfer only a serializable snapshot and restore it into a separate client-safe container.
server state -> serializable snapshot -> client state-
Make the state hydratable
Implement
Hydratable<TSnapshot>with a serializable snapshot type. -
Define a typed hydration schema
const hydration = {user: USER_STATE,} satisfies HydrationSchema; -
Create the server snapshot
const snapshot = dehydrate({container: getRequestContainer(),schema: hydration,}); -
Restore it on the client
hydrate({container: clientContainer,schema: hydration,snapshot,});
import { createContainer, createToken, provideFactory } from "di-craft";import { hydrate } from "di-craft/next/client";import { dehydrate, type Hydratable, type HydrationSchema,} from "di-craft/next/server";
type UserSnapshot = { readonly users: readonly string[];};
class UserState implements Hydratable<UserSnapshot> { private users: readonly string[] = [];
setUsers(users: readonly string[]): void { this.users = users; }
dehydrate(): UserSnapshot { return { users: this.users }; }
hydrate(snapshot: UserSnapshot): void { this.users = snapshot.users; }}
const USER_STATE = createToken<UserState>("USER_STATE");
const hydration = { user: USER_STATE,} satisfies HydrationSchema;
const serverContainer = createContainer([ provideFactory(USER_STATE, { useFactory: () => new UserState(), }),]);
serverContainer.get(USER_STATE).setUsers(["Ada", "Grace"]);
const snapshot = dehydrate({ container: serverContainer, schema: hydration,});
// The client owns a separate client-safe container. Only the serializable// snapshot crosses the server/client boundary.const clientContainer = createContainer([ provideFactory(USER_STATE, { useFactory: () => new UserState(), }),]);
hydrate({ container: clientContainer, schema: hydration, snapshot,});For streamed UI, let Suspense, loading.js, and React’s use model control the
rendering boundary. di-craft only creates the data or snapshot; it is not a
client state manager.