1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use cfg_if;
use Future;
/// Spawns and runs a thread-local [`Future`] in a platform-independent way.
///
/// This can be used to interface with any `async` code by spawning a task
/// to run a `Future`.
///
/// ## Limitations
///
/// You should not use `spawn_local` to synchronize `async` code with a
/// signal’s value during server rendering. The server response will not
/// be notified to wait for the spawned task to complete, creating a race
/// condition between the response and your task. Instead, use
/// [`create_resource`](crate::create_resource) and `<Suspense/>` to coordinate
/// asynchronous work with the rendering process.
///
/// ```
/// # use leptos::*;
/// # #[cfg(not(any(feature = "csr", feature = "serde-lite", feature = "miniserde", feature = "rkyv")))]
/// # {
///
/// async fn get_user(user: String) -> Result<String, ServerFnError> {
/// Ok(format!("this user is {user}"))
/// }
///
/// // ❌ Write into a signal from `spawn_local` on the serevr
/// #[component]
/// fn UserBad() -> impl IntoView {
/// let signal = create_rw_signal(String::new());
///
/// // ❌ If the rest of the response is already complete,
/// // `signal` will no longer exist when `get_user` resolves
/// #[cfg(feature = "ssr")]
/// spawn_local(async move {
/// let user_res = get_user("user".into()).await.unwrap_or_default();
/// signal.set(user_res);
/// });
///
/// view! {
/// <p>
/// "This will be empty (hopefully the client will render it) -> "
/// {move || signal.get()}
/// </p>
/// }
/// }
///
/// // ✅ Use a resource and suspense
/// #[component]
/// fn UserGood() -> impl IntoView {
/// // new resource with no dependencies (it will only called once)
/// let user = create_resource(|| (), |_| async { get_user("john".into()).await });
/// view! {
/// // handles the loading
/// <Suspense fallback=move || view! {<p>"Loading User"</p> }>
/// // handles the error from the resource
/// <ErrorBoundary fallback=|_| {view! {<p>"Something went wrong"</p>}}>
/// {move || {
/// user.read().map(move |x| {
/// // the resource has a result
/// x.map(move |y| {
/// // successful call from the server fn
/// view! {<p>"User result filled in server and client: "{y}</p>}
/// })
/// })
/// }}
/// </ErrorBoundary>
/// </Suspense>
/// }
/// }
/// # }
/// ```