Streaming Loaders
Ship the HTML shell immediately and stream slow loader results into stream_slot placeholders.
Enable streaming
FlowApp::new()
.streaming(true)
.auto_pages("src/pages", PagesRegistry)
.serve(FlowServeOptions::default())
.awaitDeferred loader
#[derive(Clone, Serialize, Deserialize)]
struct ProductData {
name: String,
price: u32,
}
#[load(stream)]
async fn product(req: &FlowRequest) -> ProductData {
let id = req.param("id").unwrap_or("0");
// Simulated slow query
tokio::time::sleep(std::time::Duration::from_millis(800)).await;
db::product(id).await
}Page with placeholder
pub fn page(_req: FlowRequest) -> View {
match use_product_load() {
LoadValue::Pending => view! {
<article>
<h1>"Product"</h1>
<div class="skeleton">{stream_slot("product")}</div>
</article>
},
LoadValue::Ok(data) => view! {
<article>
<h1>{data.name.clone()}</h1>
<p>"$" {data.price.to_string()}</p>
</article>
},
LoadValue::Err(e) => error_page(&FlowError::Loader(e)),
}
}User experience
Users see layout and headings instantly. Product details replace the skeleton when the loader completes — no blank screen while waiting on the database.