@@ -4,4 +4,108 @@ title: Async Resources
4
4
5
5
# Async Resources and Suspense
6
6
7
- > Note: this page is currently a stub. Help us write it!
7
+ In any real non-trivial app, you probably need to fetch data from somewhere.
8
+ This is where resources and suspense come in.
9
+
10
+ The resources API provides a simple interface for fetching and refreshing async
11
+ data and suspense makes it easy to render fallbacks while the data is loading.
12
+
13
+ ## The Resources API
14
+
15
+ To create a new resource, call the ` create_isomorphic_resource ` function.
16
+
17
+ ``` rust
18
+ use sycamore :: prelude :: * ;
19
+ use sycamore :: web :: create_isomorphic_resource;
20
+
21
+ struct Data {
22
+ // Define the data format here.
23
+ }
24
+
25
+ async fn fetch_data () -> Data {
26
+ // Perform, for instance, an HTTP request to an API endpoint.
27
+ }
28
+
29
+ let resource = create_isomorphic_resource (fetch_data );
30
+ ```
31
+
32
+ A ` Resource<T> ` is a wrapper around a ` Signal<Option<T>> ` . The value is
33
+ initially set to ` None ` while the data is loading. It is then set to ` Some(...) `
34
+ containing the value of the loaded data. This makes it convenient to display the
35
+ data in your view.
36
+
37
+ ``` rust
38
+ view! {
39
+ (if let Some (data ) = resource . get_clone () {
40
+ view! {
41
+ ...
42
+ }
43
+ } else {
44
+ view! {}
45
+ })
46
+ }
47
+ ```
48
+
49
+ Note that ` create_isomorphic_resource ` , as the name suggests, runs both on the
50
+ client and on the server. If you only want data-fetching to happen on the
51
+ client, you can use ` create_client_resource ` which will never load data on the
52
+ server.
53
+
54
+ Right now, we do not yet have a ` create_server_resource ` function which only
55
+ runs on the server because this requires some form of data-serializaation and
56
+ server-integration which we have not fully worked out yet.
57
+
58
+ ### Refreshing Resources
59
+
60
+ Resources can also have dependencies, just like memos. However, since resources
61
+ are async, we cannot track reactive dependencies like we would in a synchronous
62
+ context. Instead, we have to explicitly specify which dependencies the resource
63
+ depends on. This can be accomplished with the ` on(...) ` utility function.
64
+
65
+ ``` rust
66
+ let id = create_signal (12345 );
67
+ let resource = create_resource (on (id , move || async move {
68
+ fetch_user (id ). await
69
+ }));
70
+ ```
71
+
72
+ Under the hood, ` on(...) ` simply creates a closure that first accesses ` id ` and
73
+ then constructs the future. This makes it so that we access the signal
74
+ synchronously first before performing any asynchronous tasks.
75
+
76
+ ## Suspense
77
+
78
+ With async data, we do not want to show the UI until it is ready. This problem
79
+ is solved by the ` Suspense ` component and related APIs. When a ` Suspense `
80
+ component is created, it automatically creates a new _ suspense boundary_ . Any
81
+ asynchronous data accessed underneath this boundary will automatically be
82
+ tracked. This includes accessing resources using the resources API.
83
+
84
+ Using ` Suspense ` lets us set a fallback view to display while we are loading the
85
+ asynchronous data. For example:
86
+
87
+ ``` rust
88
+ view! {
89
+ Suspense (fallback = move || view! { LoadingSpinner {} }) {
90
+ (if let Some (data ) = resource . get_clone () {
91
+ view! {
92
+ ...
93
+ }
94
+ } else {
95
+ view! {}
96
+ })
97
+ }
98
+ }
99
+ ```
100
+
101
+ Since we are accessing ` resource ` under the suspense boundary, our ` Suspense `
102
+ component will display the fallback until the resource is loaded.
103
+
104
+ ## Transition
105
+
106
+ Resources can also be refreshed when one of its dependencies changes. This will
107
+ cause the surrounding suspense boundary to be triggered again.
108
+
109
+ This is sometimes undesired. To prevent this, just replace ` Suspense ` with
110
+ ` Transition ` . This component will continue to show the old view until the new
111
+ data has been loaded in, providing a smoother experience.
0 commit comments