Skip to main content

leptos/
await_.rs

1use crate::{prelude::Suspend, suspense_component::Suspense, IntoView};
2use leptos_macro::{component, view};
3use leptos_server::ArcOnceResource;
4use reactive_graph::prelude::ReadUntracked;
5use serde::{de::DeserializeOwned, Serialize};
6
7#[component]
8/// Allows you to inline the data loading for an `async` block or
9/// server function directly into your view. This is the equivalent of combining a
10/// [`create_resource`] that only loads once (i.e., with a source signal `|| ()`) with
11/// a [`Suspense`] with no `fallback`.
12///
13/// Adding `let:{variable name}` to the props makes the data available in the children
14/// that variable name, when resolved.
15/// ```
16/// # use leptos::prelude::*;
17/// # if false {
18/// async fn fetch_monkeys(monkey: i32) -> i32 {
19///     // do some expensive work
20///     3
21/// }
22///
23/// view! {
24///     <Await
25///         future=fetch_monkeys(3)
26///         let:data
27///     >
28///         <p>{*data} " little monkeys, jumping on the bed."</p>
29///     </Await>
30/// }
31/// # ;
32/// # }
33/// ```
34pub fn Await<T, Fut, Chil, V>(
35    /// A [`Future`](std::future::Future) that will the component will `.await`
36    /// before rendering.
37    future: Fut,
38    /// If `true`, the component will create a blocking resource, preventing
39    /// the HTML stream from returning anything before `future` has resolved.
40    #[prop(optional)]
41    blocking: bool,
42    /// A function that takes a reference to the resolved data from the `future`
43    /// renders a view.
44    ///
45    /// ## Syntax
46    /// This can be passed in the `view` children of the `<Await/>` by using the
47    /// `let:` syntax to specify the name for the data variable.
48    ///
49    /// ```rust
50    /// # use leptos::prelude::*;
51    /// # if false {
52    /// # async fn fetch_monkeys(monkey: i32) -> i32 {
53    /// #    3
54    /// # }
55    /// view! {
56    ///     <Await
57    ///         future=fetch_monkeys(3)
58    ///         let:data
59    ///     >
60    ///         <p>{*data} " little monkeys, jumping on the bed."</p>
61    ///     </Await>
62    /// }
63    /// # ;
64    /// # }
65    /// ```
66    /// is the same as
67    ///  ```rust
68    /// # use leptos::prelude::*;
69    /// # if false {
70    /// # async fn fetch_monkeys(monkey: i32) -> i32 {
71    /// #    3
72    /// # }
73    /// view! {
74    ///     <Await
75    ///         future=fetch_monkeys(3)
76    ///         children=|data| view! {
77    ///           <p>{*data} " little monkeys, jumping on the bed."</p>
78    ///         }
79    ///     />
80    /// }
81    /// # ;
82    /// # }
83    /// ```
84    children: Chil,
85) -> impl IntoView
86where
87    T: Send + Sync + Serialize + DeserializeOwned + 'static,
88    Fut: std::future::Future<Output = T> + Send + 'static,
89    Chil: FnOnce(&T) -> V + Send + 'static,
90    V: IntoView + 'static,
91{
92    let res = ArcOnceResource::<T>::new_with_options(future, blocking);
93    let ready = res.ready();
94
95    view! {
96        <Suspense fallback=|| ()>
97            {Suspend::new(async move {
98                ready.await;
99                children(res.read_untracked().as_ref().unwrap())
100            })}
101
102        </Suspense>
103    }
104}