Leptos Gotchas (0.8+)
Component Children
Section titled “Component Children”Children=Box<dyn FnOnce() -> AnyView>— rendered onceChildrenFn=Box<dyn Fn() -> AnyView>— required for conditional or repeated renderingChildrenMut=Box<dyn FnMut() -> AnyView>— when mutation between renders is needed<Show>children must beFn, notFnOnce→ useChildrenFnfor wrapper components used inside<Show>- Use
StoredValuefor non-Copy data accessed insideFnchildren (seepatterns.md)
<For> Syntax
Section titled “<For> Syntax”let:entry syntax has known issues in 0.8 (span/macro interactions) — prefer explicit children prop:
// FRAGILE — let: syntax, test carefully<For each=move || items.get() key=|item| item.id let:item> <Item item=item /></For>
// PREFERRED — explicit, no macro surprises<For each=move || items.get() key=|item| item.id children=move |item| view! { <Item item=item /> }/>Compilation
Section titled “Compilation”- Complex views can hit
queries overflow the depth limit!→ add tolib.rs:#![recursion_limit = "512"] leptos_routerandleptos_meta0.8 do not have a"hydrate"feature — onlyleptositself does- Import
web_sysasleptos::web_sys(re-exported), not as a direct crate dependency
- Prefer
Stringover&strfor component props — use.to_string()at call sites #[prop(into)]eases ergonomics for string props
WASM Safety
Section titled “WASM Safety”Server functions and anything pulling in tokio / mio are not WASM-safe.
For a crate that compiles to both SSR and WASM (e.g. a portal crate):
- Declare SSR-only deps as
optional = trueinCargo.toml - Enable them only in the
ssrfeature list - Verify with:
cargo check -p <crate> --features hydrate --target wasm32-unknown-unknown
[dependencies]my-domain = { workspace = true, optional = true } # pulls in tokio via cqrs
[features]ssr = ["dep:my-domain", ...]hydrate = [...] # must NOT include dep:my-domainA CI check against the hydrate target is the only reliable guard — the compiler will
catch any accidental SSR import in WASM-compiled code.
FnOnce in view! — the non-Copy capture problem
Section titled “FnOnce in view! — the non-Copy capture problem”A move closure that captures a non-Copy value (e.g. String) and then moves it into
a nested async move block makes the outer closure FnOnce. If that closure is inside
a view! that requires Fn (e.g. children of <Show>, reactive closures), you get:
expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`See patterns.md — StoredValue vs Double-Clone — for the two canonical fixes.