Leptos Hydrated
A library for flicker-free interactive state hydration in Leptos 0.8.
leptos_hydrated is ideal for bootstrapping state that you already have or can have on both sides (isomorphic data), such as cookies or URL parameters. By initializing signals immediately with server-provided state and synchronizing them once the browser is active, you eliminate the "loading flicker" common in SSR applications.
How it Works
- Server-Side Render (SSR):
initial()is called on the server. The result is serialized into a deterministic injection stream in the HTML shell. - Hydration: The client reads the serialized state from the stream in the same order and initializes the signal immediately: zero flicker.
- Synchronization: Once the WASM is active,
initial()is re-run on the client to synchronize with the current browser state (e.g., reading a JS-accessible cookie). - Lifecycle Hooks: Use
on_hydrateto execute any client-side code immediately after hydration (e.g., event listeners).
Hydration Accessors
leptos_hydrated mirrors standard Leptos signal patterns to make state management intuitive.
1. Local (Independent)
Use hydrated_signal to create a new, independent hydrated signal. This works exactly like RwSignal::new(T), but it is hydration-aware.
2. Scoped (Shared)
Wrap a section of your component tree with <HydratedContext<T>> to share a hydrated signal. Use use_hydrated_context<T>() in descendants to access it.
3. Global (Shared)
Use <HydratedContext<T> global=true /> (typically in your app shell) to provide state globally across your entire application.
Quick Start
1. Define your State with Hydratable
Implement the Hydratable trait to define how your state is initialized and synchronized.
use *;
use *;
use ;
;
Bundle Size Optimization
leptos_hydrated is designed to keep your client-side WASM bundles as lean as possible. By default, Leptos server functions rely on serde_json for communication, which can add ~150-200 KB to your WASM binary.
#[hydrated_server]
Use the #[hydrated_server] macro instead of standard #[server] to eliminate serde_json from your frontend. It uses the browser's native JSON primitives for serialization/deserialization.
pub async
This optimization is fully compatible with ActionForm and standard ServerAction patterns.
Server-Side Setup
1. Middleware
You must add the .hydrated() middleware to your Axum router.
// src/main.rs (Server)
use HydratedRouterExt;
let app = new
.leptos_routes
.fallback
.hydrated // <--- Add this before .with_state()
.with_state;
Isomorphic Helpers
get_cookie(name): Reads a cookie by name.set_cookie(name, value, options): Sets a cookie.get_query_param(name): Reads a URL query parameter.
Utilities
isomorphic! { state => ..., hydrate => ... }: Branch logic for server-seed vs client-hydration.use_hydrated_context<T>(): Accesses state from context (returnsOption<RwSignal<T>>).