mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
* Make a use_hook hook with the new Hook trait. * Implement Lifetime. * Rewrites function signature. * Only apply lifetime if there're other lifetimes. * Cleanup signature rewrite logic. * Rewrite hook body. * Port some built-in hooks. * Finish porting all built-in hooks. * Port tests. * Fix tests. * Migrate to macro-based hooks. * Fix HookContext, add tests on non-possible locations. * Fix stderr for trybuild. * Add 1 more test case. * Adjust doc location. * Pretty print hook signature. * Fix Items & std::ops::Fn*. * Add use_memo. * Optimise Implementation of hooks. * Use Box to capture function value only. * Detect whether needs boxing. * Add args if boxing not needed. * Enforce hook number. * Deduplicate use_effect. * Optimise Implementation. * Update documentation. * Fix website test. Strip BoxedHook implementation from it. * Allow doc string. * Workaround doc tests. * Optimise codebase & documentation. * Fix website test. * Reduce implementation complexity. * Destructor is no more. * Documentation and macros. * Reduce heap allocation and hook complexity. * Remove Queue as well. * Prefer Generics. * Fix typo. * Remove more allocations. * Add comments. * Remove outdated comment. * Bare Function Pointer for better code size.
183 lines
4.4 KiB
Plaintext
183 lines
4.4 KiB
Plaintext
---
|
|
title: "Suspense"
|
|
description: "Suspense for data fetching"
|
|
---
|
|
|
|
Suspense is a way to suspend component rendering whilst waiting a task
|
|
to complete and a fallback (placeholder) UI is shown in the meanwhile.
|
|
|
|
It can be used to fetch data from server, wait for tasks to be completed
|
|
by an agent, or perform other background asynchronous task.
|
|
|
|
Before suspense, data fetching usually happens after (Fetch-on-render) or before
|
|
component rendering (Fetch-then-render).
|
|
|
|
### Render-as-You-Fetch
|
|
|
|
Suspense enables a new approach that allows components to initiate data request
|
|
during the rendering process. When a component initiates a data request,
|
|
the rendering process will become suspended and a fallback UI will be
|
|
shown until the request is completed.
|
|
|
|
The recommended way to use suspense is with hooks.
|
|
|
|
```rust ,ignore
|
|
use yew::prelude::*;
|
|
|
|
#[function_component(Content)]
|
|
fn content() -> HtmlResult {
|
|
let user = use_user()?;
|
|
|
|
Ok(html! {<div>{"Hello, "}{&user.name}</div>})
|
|
}
|
|
|
|
#[function_component(App)]
|
|
fn app() -> Html {
|
|
let fallback = html! {<div>{"Loading..."}</div>};
|
|
|
|
html! {
|
|
<Suspense {fallback}>
|
|
<Content />
|
|
</Suspense>
|
|
}
|
|
}
|
|
```
|
|
|
|
In the above example, the `use_user` hook will suspend the component
|
|
rendering while user information is loading and a `Loading...` placeholder will
|
|
be shown until `user` is loaded.
|
|
|
|
To define a hook that suspends a component rendering, it needs to return
|
|
a `SuspensionResult<T>`. When the component needs to be suspended, the
|
|
hook should return a `Err(Suspension)` and users should unwrap it with
|
|
`?` in which it will be converted into `Html`.
|
|
|
|
```rust ,ignore
|
|
use yew::prelude::*;
|
|
use yew::suspense::{Suspension, SuspensionResult};
|
|
|
|
struct User {
|
|
name: String,
|
|
}
|
|
|
|
#[hook]
|
|
fn use_user() -> SuspensionResult<User> {
|
|
match load_user() {
|
|
// If a user is loaded, then we return it as Ok(user).
|
|
Some(m) => Ok(m),
|
|
None => {
|
|
// When user is still loading, then we create a `Suspension`
|
|
// and call `SuspensionHandle::resume` when data loading
|
|
// completes, the component will be re-rendered
|
|
// automatically.
|
|
let (s, handle) = Suspension::new();
|
|
on_load_user_complete(move || {handle.resume();});
|
|
Err(s)
|
|
},
|
|
}
|
|
}
|
|
```
|
|
|
|
# Complete Example
|
|
|
|
```rust
|
|
use yew::prelude::*;
|
|
use yew::suspense::{Suspension, SuspensionResult};
|
|
|
|
#[derive(Debug)]
|
|
struct User {
|
|
name: String,
|
|
}
|
|
|
|
fn load_user() -> Option<User> {
|
|
todo!() // implementation omitted.
|
|
}
|
|
|
|
fn on_load_user_complete<F: FnOnce()>(_fn: F) {
|
|
todo!() // implementation omitted.
|
|
}
|
|
|
|
#[hook]
|
|
fn use_user() -> SuspensionResult<User> {
|
|
match load_user() {
|
|
// If a user is loaded, then we return it as Ok(user).
|
|
Some(m) => Ok(m),
|
|
None => {
|
|
// When user is still loading, then we create a `Suspension`
|
|
// and call `SuspensionHandle::resume` when data loading
|
|
// completes, the component will be re-rendered
|
|
// automatically.
|
|
let (s, handle) = Suspension::new();
|
|
on_load_user_complete(move || {handle.resume();});
|
|
Err(s)
|
|
},
|
|
}
|
|
}
|
|
|
|
#[function_component(Content)]
|
|
fn content() -> HtmlResult {
|
|
let user = use_user()?;
|
|
|
|
Ok(html! {<div>{"Hello, "}{&user.name}</div>})
|
|
}
|
|
|
|
#[function_component(App)]
|
|
fn app() -> Html {
|
|
let fallback = html! {<div>{"Loading..."}</div>};
|
|
|
|
html! {
|
|
<Suspense {fallback}>
|
|
<Content />
|
|
</Suspense>
|
|
}
|
|
}
|
|
```
|
|
|
|
|
|
### Use Suspense in Struct Components
|
|
|
|
It's not possible to suspend a struct component directly. However, you
|
|
can use a function component as a Higher-Order-Component to
|
|
achieve suspense-based data fetching.
|
|
|
|
```rust ,ignore
|
|
use yew::prelude::*;
|
|
|
|
#[function_component(WithUser)]
|
|
fn with_user<T>() -> HtmlResult
|
|
where T: BaseComponent
|
|
{
|
|
let user = use_user()?;
|
|
|
|
Ok(html! {<T {user} />})
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Properties)]
|
|
pub struct UserContentProps {
|
|
pub user: User,
|
|
}
|
|
|
|
pub struct BaseUserContent;
|
|
|
|
impl Component for BaseUserContent {
|
|
type Properties = UserContentProps;
|
|
type Message = ();
|
|
|
|
fn create(ctx: &Context<Self>) -> Self {
|
|
Self
|
|
}
|
|
|
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
let name = ctx.props().user.name;
|
|
|
|
html! {<div>{"Hello, "}{name}{"!"}</div>}
|
|
}
|
|
}
|
|
|
|
pub type UserContent = WithUser<BaseUserContent>;
|
|
```
|
|
|
|
## Relevant examples
|
|
|
|
- [Suspense](https://github.com/yewstack/yew/tree/master/examples/suspense)
|