From dd9edca804f74baccc487055c584b786bd3bc478 Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Fri, 10 Apr 2026 10:55:43 +0200
Subject: [PATCH 1/8] docs: tutorial(0.23): update outdated fetching data
section
Fetching data section of the tutorial page still mentioned using
`wasm-bindgen-futures::spawn_local`. Updated the docs and examples to use
`yew::platform::spawn_local` and the `use_future` hook instead.
---
.../version-0.23/tutorial/index.mdx | 121 ++++++++++++++----
1 file changed, 93 insertions(+), 28 deletions(-)
diff --git a/website/versioned_docs/version-0.23/tutorial/index.mdx b/website/versioned_docs/version-0.23/tutorial/index.mdx
index 4b13c2d931d..a86616db445 100644
--- a/website/versioned_docs/version-0.23/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.23/tutorial/index.mdx
@@ -479,7 +479,6 @@ Let's update the dependencies in `Cargo.toml` file:
+yew = { version = "0.23", features = ["csr", "serde"] }
+gloo-net = "0.6"
+serde = { version = "1.0", features = ["derive"] }
-+wasm-bindgen-futures = "0.4"
```
Yew's `serde` feature enables integration with the `serde` crate, the important point for us is that
@@ -506,12 +505,70 @@ struct Video {
}
```
-Now as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data
+Now we need to update our `App` component to fetch data. The modern yew way to do this is with
-```rust {2,6-50,59-60}
+[`use_future`](https://docs.rs/yew/0.23.0/yew/suspense/fn.use_future.html) and
+[``](https://yew.rs/docs/concepts/suspense).
+
+Alternatively, you can use [`yew::platform::spawn_local`](https://docs.rs/yew/latest/yew/platform/fn.spawn_local.html)
+if hooks are unavailable, such as within struct components or standard functions.
+
+`use_future` suspends the component until the async operation completes, and `` shows a
+fallback UI (e.g. a loading indicator) in the meantime.
+
+We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
+while the parent `App` wraps it in ``:
+
+```rust {3-4}
use yew::prelude::*;
+use serde::Deserialize;
+use gloo_net::http::Request;
++use yew::suspense::use_future;
+// ..
++#[derive(Properties, PartialEq)]
++struct VideosFetchProps {
++ on_click: Callback
++ if let Some(video) = selected_video {
++
++ }
++ >
++ }),
++ Err(err) => Ok(html! {
++ {format!("Error fetching videos: {err}")}
++ }),
++ }
++}
+```
+
+Now we will use the new component inside the App component.
+```rust {4-30,37-46}
+// ..
#[component]
fn App() -> Html {
- let videos = vec![
@@ -541,46 +598,54 @@ fn App() -> Html {
- },
- ];
-
-+ let videos = use_state(|| vec![]);
-+ {
-+ let videos = videos.clone();
-+ use_effect_with((), move |_| {
-+ let videos = videos.clone();
-+ wasm_bindgen_futures::spawn_local(async move {
-+ let fetched_videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ .send()
-+ .await
-+ .unwrap()
-+ .json()
-+ .await
-+ .unwrap();
-+ videos.set(fetched_videos);
-+ });
-+ || ()
-+ });
-+ }
// ...
html! {
<>
{ "RustConf Explorer" }
-
-
{ "Videos to watch" }
+-
+-
{ "Videos to watch" }
-
-+
-
- // ...
+-
++ {"Loading..."} }} >
++
++
>
}
}
```
:::note
-We are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have
-[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).
+We use `?` on the `use_future` call to propagate the suspension. The component returns `HtmlResult`
+instead of `Html` when using suspense hooks. The parent wraps it in `` to show
+a loading indicator while the data is being fetched.
:::
+The loading text may not be visible because the data loads very quickly. If you'd like to see it, you can add an
+artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add `gloo-timers` to your `Cargo.toml`:
+
+```toml
+gloo-timers = { version = "0.3", features = ["futures"] }
+```
+Then add the delay inside the hook:
+
+```rust
+use gloo_timers::future::TimeoutFuture;
+
+let videos = use_future(|| async {
++ TimeoutFuture::new(3_000).await; // 3 second delay
+ Request::get("/tutorial/data.json")
+ .send()
+ .await?
+ .json::>()
+ .await
+})?;
+```
+
Now, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.
To fix that, we need a proxy server. Luckily trunk provides that.
From 5b02b955bd561eacd28ced68f36c21624466ce5b Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Sun, 19 Apr 2026 16:49:20 +0200
Subject: [PATCH 2/8] docs: 0.23: remove wasm-bindgen-futures link and fix
order of the sections
The wasm-bindgen-futures was still present in the docs, so removed it.
Adding the delay to see the loading should have been a last section so
moved it to the end. Removed the path and populated the same with the
full link, as later in the docs to fix the cors issue we are asking the
user to replace the full link with the path.
---
.../version-0.23/tutorial/index.mdx | 47 +++++++++----------
1 file changed, 21 insertions(+), 26 deletions(-)
diff --git a/website/versioned_docs/version-0.23/tutorial/index.mdx b/website/versioned_docs/version-0.23/tutorial/index.mdx
index a86616db445..6dffe1349eb 100644
--- a/website/versioned_docs/version-0.23/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.23/tutorial/index.mdx
@@ -468,8 +468,6 @@ videos list from an external source. For this we will need to add the following
For making the fetch call.
- [`serde`](https://serde.rs) with derive features
For de-serializing the JSON response
-- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)
- For executing Rust Future as a Promise
Let's update the dependencies in `Cargo.toml` file:
@@ -505,10 +503,7 @@ struct Video {
}
```
-Now we need to update our `App` component to fetch data. The modern yew way to do this is with
-
-[`use_future`](https://docs.rs/yew/0.23.0/yew/suspense/fn.use_future.html) and
-[``](https://yew.rs/docs/concepts/suspense).
+Now we need to update our `App` component to fetch data. The modern yew way to do this is with [`use_future`](https://docs.rs/yew/0.23.0/yew/suspense/fn.use_future.html) and [``](https://yew.rs/docs/concepts/suspense).
Alternatively, you can use [`yew::platform::spawn_local`](https://docs.rs/yew/latest/yew/platform/fn.spawn_local.html)
if hooks are unavailable, such as within struct components or standard functions.
@@ -519,7 +514,7 @@ fallback UI (e.g. a loading indicator) in the meantime.
We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
while the parent `App` wraps it in ``:
-```rust {3-4}
+```rust {3-4,6-10,12-43}
use yew::prelude::*;
use serde::Deserialize;
+use gloo_net::http::Request;
@@ -539,7 +534,7 @@ use serde::Deserialize;
+ }: &VideosFetchProps,
+) -> HtmlResult {
+ let videos = use_future(|| async {
-+ Request::get("/tutorial/data.json")
++ Request::get("https://yew.rs/tutorial/data.json")
+ .send()
+ .await?
+ .json::>()
@@ -625,6 +620,24 @@ instead of `Html` when using suspense hooks. The parent wraps it in ` = Request::get("https://yew.rs/tutorial/data.json")
++ let videos: Vec = Request::get("/tutorial/data.json")
+```
+
+Now, rerun the server with the following command:
+
+```bash
+trunk serve --proxy-backend=https://yew.rs/tutorial
+```
+
+Refresh the tab and everything should work as expected.
+
The loading text may not be visible because the data loads very quickly. If you'd like to see it, you can add an
artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add `gloo-timers` to your `Cargo.toml`:
@@ -646,24 +659,6 @@ let videos = use_future(|| async {
})?;
```
-Now, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.
-To fix that, we need a proxy server. Luckily trunk provides that.
-
-Update the following line:
-
-```rust {2-3}
-- let fetched_videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ let fetched_videos: Vec = Request::get("/tutorial/data.json")
-```
-
-Now, rerun the server with the following command:
-
-```bash
-trunk serve --proxy-backend=https://yew.rs/tutorial
-```
-
-Refresh the tab and everything should work as expected.
-
## Wrapping up
Congratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.
From 0dc6da81b09d746165c81b77c54dc26eb1b767a7 Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Sun, 19 Apr 2026 16:50:15 +0200
Subject: [PATCH 3/8] docs: tutorial(0.22): update outdated fetching data
section
---
.../version-0.22/tutorial/index.mdx | 125 +++++++++++++-----
1 file changed, 92 insertions(+), 33 deletions(-)
diff --git a/website/versioned_docs/version-0.22/tutorial/index.mdx b/website/versioned_docs/version-0.22/tutorial/index.mdx
index 98c606e7897..e66bbf25a65 100644
--- a/website/versioned_docs/version-0.22/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.22/tutorial/index.mdx
@@ -460,7 +460,6 @@ Struct components act differently. See [the documentation](advanced-topics/struc
:::
## Fetching data (using external REST API)
-
In a real-world application, data will usually come from an API instead of being hardcoded. Let's fetch our
videos list from an external source. For this we will need to add the following crates:
@@ -468,8 +467,6 @@ videos list from an external source. For this we will need to add the following
For making the fetch call.
- [`serde`](https://serde.rs) with derive features
For de-serializing the JSON response
-- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)
- For executing Rust Future as a Promise
Let's update the dependencies in `Cargo.toml` file:
@@ -479,7 +476,6 @@ Let's update the dependencies in `Cargo.toml` file:
+yew = { version = "0.22", features = ["csr", "serde"] }
+gloo-net = "0.6"
+serde = { version = "1.0", features = ["derive"] }
-+wasm-bindgen-futures = "0.4"
```
Yew's `serde` feature enables integration with the `serde` crate, the important point for us is that
@@ -506,12 +502,67 @@ struct Video {
}
```
-Now as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data
+Now we need to update our `App` component to fetch data. The modern yew way to do this is with [`use_future`](https://docs.rs/yew/0.22.0/yew/suspense/fn.use_future.html) and [``](https://yew.rs/docs/concepts/suspense).
+
+Alternatively, you can use [`yew::platform::spawn_local`](https://docs.rs/yew/0.22.0/yew/platform/fn.spawn_local.html)
+if hooks are unavailable, such as within struct components or standard functions.
+
+`use_future` suspends the component until the async operation completes, and `` shows a
+fallback UI (e.g. a loading indicator) in the meantime.
-```rust {2,6-50,59-60}
+We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
+while the parent `App` wraps it in ``:
+
+```rust {3-4,6-10,12-43}
use yew::prelude::*;
+use serde::Deserialize;
+use gloo_net::http::Request;
++use yew::suspense::use_future;
+// ..
++#[derive(Properties, PartialEq)]
++struct VideosFetchProps {
++ on_click: Callback,
++ selected_video: Option,
++}
+
++#[component]
++fn VideosFetcher(
++ VideosFetchProps {
++ on_click,
++ selected_video,
++ }: &VideosFetchProps,
++) -> HtmlResult {
++ let videos = use_future(|| async {
++ Request::get("https://yew.rs/tutorial/data.json")
++ .send()
++ .await?
++ .json::>()
++ .await
++ })?;
++
++ match &*videos {
++ Ok(videos) => Ok(html! {
++ <>
++
++
{ "Videos to watch" }
++
++
++ if let Some(video) = selected_video {
++
++ }
++ >
++ }),
++ Err(err) => Ok(html! {
++ {format!("Error fetching videos: {err}")}
++ }),
++ }
++}
+```
+
+Now we will use the new component inside the App component.
+```rust {4-30,37-46}
+// ..
#[component]
fn App() -> Html {
- let videos = vec![
@@ -541,44 +592,31 @@ fn App() -> Html {
- },
- ];
-
-+ let videos = use_state(|| vec![]);
-+ {
-+ let videos = videos.clone();
-+ use_effect_with((), move |_| {
-+ let videos = videos.clone();
-+ wasm_bindgen_futures::spawn_local(async move {
-+ let fetched_videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ .send()
-+ .await
-+ .unwrap()
-+ .json()
-+ .await
-+ .unwrap();
-+ videos.set(fetched_videos);
-+ });
-+ || ()
-+ });
-+ }
// ...
html! {
<>
{ "RustConf Explorer" }
-
-
{ "Videos to watch" }
+-
+-
{ "Videos to watch" }
-
-+
-
- // ...
+-
++ {"Loading..."} }} >
++
++
>
}
}
```
:::note
-We are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have
-[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).
+We use `?` on the `use_future` call to propagate the suspension. The component returns `HtmlResult`
+instead of `Html` when using suspense hooks. The parent wraps it in `` to show
+a loading indicator while the data is being fetched.
:::
Now, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.
@@ -587,8 +625,8 @@ To fix that, we need a proxy server. Luckily trunk provides that.
Update the following line:
```rust {2-3}
-- let fetched_videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ let fetched_videos: Vec = Request::get("/tutorial/data.json")
+- let videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
++ let videos: Vec = Request::get("/tutorial/data.json")
```
Now, rerun the server with the following command:
@@ -599,6 +637,27 @@ trunk serve --proxy-backend=https://yew.rs/tutorial
Refresh the tab and everything should work as expected.
+The loading text may not be visible because the data loads very quickly. If you'd like to see it, you can add an
+artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add `gloo-timers` to your `Cargo.toml`:
+
+```toml
+gloo-timers = { version = "0.3", features = ["futures"] }
+```
+Then add the delay inside the hook:
+
+```rust
+use gloo_timers::future::TimeoutFuture;
+
+let videos = use_future(|| async {
++ TimeoutFuture::new(3_000).await; // 3 second delay
+ Request::get("/tutorial/data.json")
+ .send()
+ .await?
+ .json::>()
+ .await
+})?;
+```
+
## Wrapping up
Congratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.
From 71680405ffc3532a8b5c99b1a5975c9fc25a263d Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Sun, 19 Apr 2026 22:02:32 +0200
Subject: [PATCH 4/8] docs: tutorial(next): update outdate fetching data
section
---
website/docs/tutorial/index.mdx | 130 +++++++++++++++++++++++---------
1 file changed, 96 insertions(+), 34 deletions(-)
diff --git a/website/docs/tutorial/index.mdx b/website/docs/tutorial/index.mdx
index 5cefaf1b9d1..e410a2b3fb9 100644
--- a/website/docs/tutorial/index.mdx
+++ b/website/docs/tutorial/index.mdx
@@ -459,8 +459,6 @@ videos list from an external source. For this we will need to add the following
For making the fetch call.
- [`serde`](https://serde.rs) with derive features
For de-serializing the JSON response
-- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures)
- For executing Rust Future as a Promise
Let's update the dependencies in `Cargo.toml` file:
@@ -470,7 +468,6 @@ Let's update the dependencies in `Cargo.toml` file:
+yew = { git = "https://github.com/yewstack/yew/", features = ["csr", "serde"] }
+gloo-net = "0.6"
+serde = { version = "1.0", features = ["derive"] }
-+wasm-bindgen-futures = "0.4"
```
Yew's `serde` feature enables integration with the `serde` crate, the important point for us is that
@@ -497,12 +494,67 @@ struct Video {
}
```
-Now as the last step, we need to update our `App` component to make the fetch request instead of using hardcoded data
+Now we need to update our `App` component to fetch data. The modern yew way to do this is with [`use_future`](https://docs.rs/yew/0.23.0/yew/suspense/fn.use_future.html) and [``](https://yew.rs/docs/concepts/suspense).
-```rust {2,6-50,59-60}
+Alternatively, you can use [`yew::platform::spawn_local`](https://docs.rs/yew/latest/yew/platform/fn.spawn_local.html)
+if hooks are unavailable, such as within struct components or standard functions.
+
+`use_future` suspends the component until the async operation completes, and `` shows a
+fallback UI (e.g. a loading indicator) in the meantime.
+
+We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
+while the parent `App` wraps it in ``:
+
+```rust {3-4,6-10,12-43}
use yew::prelude::*;
+use serde::Deserialize;
+use gloo_net::http::Request;
++use yew::suspense::use_future;
+// ..
++#[derive(Properties, PartialEq)]
++struct VideosFetchProps {
++ on_click: Callback,
++ selected_video: Option,
++}
+
++#[component]
++fn VideosFetcher(
++ VideosFetchProps {
++ on_click,
++ selected_video,
++ }: &VideosFetchProps,
++) -> HtmlResult {
++ let videos = use_future(|| async {
++ Request::get("https://yew.rs/tutorial/data.json")
++ .send()
++ .await?
++ .json::>()
++ .await
++ })?;
++
++ match &*videos {
++ Ok(videos) => Ok(html! {
++ <>
++
++
{ "Videos to watch" }
++
++
++ if let Some(video) = selected_video {
++
++ }
++ >
++ }),
++ Err(err) => Ok(html! {
++ {format!("Error fetching videos: {err}")}
++ }),
++ }
++}
+```
+Now we will use the new component inside the App component.
+
+```rust {4-30,37-46}
+// ..
#[component]
fn App() -> Html {
- let videos = vec![
@@ -532,42 +584,31 @@ fn App() -> Html {
- },
- ];
-
-+ let videos = use_state(|| vec![]);
-+ {
-+ let videos = videos.clone();
-+ use_effect_with((), move |_| {
-+ let videos = videos.clone();
-+ wasm_bindgen_futures::spawn_local(async move {
-+ let fetched_videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ .send()
-+ .await
-+ .unwrap()
-+ .json()
-+ .await
-+ .unwrap();
-+ videos.set(fetched_videos);
-+ });
-+ || ()
-+ });
-+ }
// ...
html! {
- { "RustConf Explorer" }
-
-
{ "Videos to watch" }
--
-+
-
- // ...
+ <>
+ { "RustConf Explorer" }
+-
+-
{ "Videos to watch" }
+-
+-
++ {"Loading..."} }} >
++
++
+ >
}
}
```
:::note
-We are using `unwrap`s here because this is a demo application. In a real-world app, you would likely want to have
-[proper error handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html).
+We use `?` on the `use_future` call to propagate the suspension. The component returns `HtmlResult`
+instead of `Html` when using suspense hooks. The parent wraps it in `` to show
+a loading indicator while the data is being fetched.
:::
Now, look at the browser to see everything working as expected... which would have been the case if it were not for CORS.
@@ -576,8 +617,8 @@ To fix that, we need a proxy server. Luckily trunk provides that.
Update the following line:
```rust {2-3}
-- let fetched_videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ let fetched_videos: Vec = Request::get("/tutorial/data.json")
+- let videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
++ let videos: Vec = Request::get("/tutorial/data.json")
```
Now, rerun the server with the following command:
@@ -588,6 +629,27 @@ trunk serve --proxy-backend=https://yew.rs/tutorial
Refresh the tab and everything should work as expected.
+The loading text may not be visible because the data loads very quickly. If you'd like to see it, you can add an
+artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add `gloo-timers` to your `Cargo.toml`:
+
+```toml
+gloo-timers = { version = "0.3", features = ["futures"] }
+```
+Then add the delay inside the hook:
+
+```rust
+use gloo_timers::future::TimeoutFuture;
+
+let videos = use_future(|| async {
++ TimeoutFuture::new(3_000).await; // 3 second delay
+ Request::get("/tutorial/data.json")
+ .send()
+ .await?
+ .json::>()
+ .await
+})?;
+```
+
## Wrapping up
Congratulations! You’ve created a web application that fetches data from an external API and displays a list of videos.
From 6deca004be497f8a88dee63ef460b6aad4a066ce Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Tue, 21 Apr 2026 22:17:49 +0200
Subject: [PATCH 5/8] revert newline removal from 0.22 docs
---
website/versioned_docs/version-0.22/tutorial/index.mdx | 1 +
1 file changed, 1 insertion(+)
diff --git a/website/versioned_docs/version-0.22/tutorial/index.mdx b/website/versioned_docs/version-0.22/tutorial/index.mdx
index e66bbf25a65..5691df3d69e 100644
--- a/website/versioned_docs/version-0.22/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.22/tutorial/index.mdx
@@ -460,6 +460,7 @@ Struct components act differently. See [the documentation](advanced-topics/struc
:::
## Fetching data (using external REST API)
+
In a real-world application, data will usually come from an API instead of being hardcoded. Let's fetch our
videos list from an external source. For this we will need to add the following crates:
From 5897a251a9ae1b6857bb5baf8774cf9defb36ef9 Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Sun, 26 Apr 2026 22:14:17 +0200
Subject: [PATCH 6/8] ci: tutorial: fix failing tests while applying the diff
---
website/docs/tutorial/index.mdx | 59 ++++++++++++++++++---------------
1 file changed, 33 insertions(+), 26 deletions(-)
diff --git a/website/docs/tutorial/index.mdx b/website/docs/tutorial/index.mdx
index e410a2b3fb9..b36b3e7a7de 100644
--- a/website/docs/tutorial/index.mdx
+++ b/website/docs/tutorial/index.mdx
@@ -478,12 +478,16 @@ When choosing dependencies make sure they are `wasm32` compatible!
Otherwise you won't be able to run your application.
:::
-Update the `Video` struct to derive the `Deserialize` trait:
+Update the imports:
-```rust {2,4-5}
+```rust {2}
use yew::prelude::*;
+use serde::Deserialize;
-// ...
+```
+
+Update the `Video` struct to derive the `Deserialize` trait:
+
+```rust {2,4-5}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Deserialize)]
struct Video {
@@ -505,12 +509,17 @@ fallback UI (e.g. a loading indicator) in the meantime.
We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
while the parent `App` wraps it in ``:
-```rust {3-4,6-10,12-43}
+Update the imports:
+
+```rust {3-4}
use yew::prelude::*;
use serde::Deserialize;
+use gloo_net::http::Request;
+use yew::suspense::use_future;
-// ..
+```
+
+```rust {3-4,6-10,12-43}
+use yew::suspense::use_future;
+#[derive(Properties, PartialEq)]
+struct VideosFetchProps {
+ on_click: Callback,
@@ -551,10 +560,9 @@ use serde::Deserialize;
+}
```
-Now we will use the new component inside the App component.
+Now we will use the new component inside the App component.
```rust {4-30,37-46}
-// ..
#[component]
fn App() -> Html {
- let videos = vec![
@@ -588,19 +596,20 @@ fn App() -> Html {
// ...
html! {
- <>
- { "RustConf Explorer" }
--
--
{ "Videos to watch" }
--
--
-+ {"Loading..."} }} >
-+
-+
- >
+- { "RustConf Explorer" }
+-
+-
{ "Videos to watch" }
+-
+-
++ <>
++ { "RustConf Explorer" }
++ {"Loading..."} }} >
++
++
++ >
}
}
```
@@ -617,8 +626,8 @@ To fix that, we need a proxy server. Luckily trunk provides that.
Update the following line:
```rust {2-3}
-- let videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ let videos: Vec = Request::get("/tutorial/data.json")
+- Request::get("https://yew.rs/tutorial/data.json")
++ Request::get("/tutorial/data.json")
```
Now, rerun the server with the following command:
@@ -637,11 +646,9 @@ gloo-timers = { version = "0.3", features = ["futures"] }
```
Then add the delay inside the hook:
-```rust
-use gloo_timers::future::TimeoutFuture;
-
+```ignore
let videos = use_future(|| async {
-+ TimeoutFuture::new(3_000).await; // 3 second delay
++ gloo_timers::future::TimeoutFuture::new(3_000).await; // 3 second delay
Request::get("/tutorial/data.json")
.send()
.await?
From 40f383c1b9cae3dc12d3d98f9e7029012a404102 Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Sun, 26 Apr 2026 23:07:16 +0200
Subject: [PATCH 7/8] cleanup: fix highlighting and reorder some code snippets
---
website/docs/tutorial/index.mdx | 16 ++---
.../version-0.22/tutorial/index.mdx | 67 ++++++++++---------
.../version-0.23/tutorial/index.mdx | 67 ++++++++++---------
3 files changed, 82 insertions(+), 68 deletions(-)
diff --git a/website/docs/tutorial/index.mdx b/website/docs/tutorial/index.mdx
index b36b3e7a7de..674b6a1ce3e 100644
--- a/website/docs/tutorial/index.mdx
+++ b/website/docs/tutorial/index.mdx
@@ -487,7 +487,7 @@ use yew::prelude::*;
Update the `Video` struct to derive the `Deserialize` trait:
-```rust {2,4-5}
+```rust {2}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Deserialize)]
struct Video {
@@ -506,9 +506,6 @@ if hooks are unavailable, such as within struct components or standard functions
`use_future` suspends the component until the async operation completes, and `` shows a
fallback UI (e.g. a loading indicator) in the meantime.
-We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
-while the parent `App` wraps it in ``:
-
Update the imports:
```rust {3-4}
@@ -518,7 +515,10 @@ use serde::Deserialize;
+use yew::suspense::use_future;
```
-```rust {3-4,6-10,12-43}
+We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
+while the parent `App` wraps it in ``:
+
+```rust {2-6,7-39}
use yew::suspense::use_future;
+#[derive(Properties, PartialEq)]
+struct VideosFetchProps {
@@ -562,7 +562,7 @@ use yew::suspense::use_future;
Now we will use the new component inside the App component.
-```rust {4-30,37-46}
+```rust {3-30,37-46}
#[component]
fn App() -> Html {
- let videos = vec![
@@ -625,7 +625,7 @@ To fix that, we need a proxy server. Luckily trunk provides that.
Update the following line:
-```rust {2-3}
+```rust {1-2}
- Request::get("https://yew.rs/tutorial/data.json")
+ Request::get("/tutorial/data.json")
```
@@ -646,7 +646,7 @@ gloo-timers = { version = "0.3", features = ["futures"] }
```
Then add the delay inside the hook:
-```ignore
+```
let videos = use_future(|| async {
+ gloo_timers::future::TimeoutFuture::new(3_000).await; // 3 second delay
Request::get("/tutorial/data.json")
diff --git a/website/versioned_docs/version-0.22/tutorial/index.mdx b/website/versioned_docs/version-0.22/tutorial/index.mdx
index 5691df3d69e..9da985f414f 100644
--- a/website/versioned_docs/version-0.22/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.22/tutorial/index.mdx
@@ -487,12 +487,16 @@ When choosing dependencies make sure they are `wasm32` compatible!
Otherwise you won't be able to run your application.
:::
-Update the `Video` struct to derive the `Deserialize` trait:
+Update the imports:
-```rust {2,4-5}
+```rust {2}
use yew::prelude::*;
+use serde::Deserialize;
-// ...
+```
+
+Update the `Video` struct to derive the `Deserialize` trait:
+
+```rust {2}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Deserialize)]
struct Video {
@@ -511,15 +515,20 @@ if hooks are unavailable, such as within struct components or standard functions
`use_future` suspends the component until the async operation completes, and `` shows a
fallback UI (e.g. a loading indicator) in the meantime.
-We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
-while the parent `App` wraps it in ``:
+Update the imports:
-```rust {3-4,6-10,12-43}
+```rust {3-4}
use yew::prelude::*;
use serde::Deserialize;
+use gloo_net::http::Request;
+use yew::suspense::use_future;
-// ..
+```
+
+We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
+while the parent `App` wraps it in ``:
+
+```rust {2-6,7-39}
+use yew::suspense::use_future;
+#[derive(Properties, PartialEq)]
+struct VideosFetchProps {
+ on_click: Callback,
@@ -562,8 +571,7 @@ use serde::Deserialize;
Now we will use the new component inside the App component.
-```rust {4-30,37-46}
-// ..
+```rust {3-30,37-46}
#[component]
fn App() -> Html {
- let videos = vec![
@@ -597,19 +605,20 @@ fn App() -> Html {
// ...
html! {
- <>
- { "RustConf Explorer" }
--
--
{ "Videos to watch" }
--
--
-+ {"Loading..."} }} >
-+
-+
- >
+- { "RustConf Explorer" }
+-
+-
{ "Videos to watch" }
+-
+-
++ <>
++ { "RustConf Explorer" }
++ {"Loading..."} }} >
++
++
++ >
}
}
```
@@ -625,9 +634,9 @@ To fix that, we need a proxy server. Luckily trunk provides that.
Update the following line:
-```rust {2-3}
-- let videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ let videos: Vec = Request::get("/tutorial/data.json")
+```rust {1-2}
+- Request::get("https://yew.rs/tutorial/data.json")
++ Request::get("/tutorial/data.json")
```
Now, rerun the server with the following command:
@@ -646,17 +655,15 @@ gloo-timers = { version = "0.3", features = ["futures"] }
```
Then add the delay inside the hook:
-```rust
-use gloo_timers::future::TimeoutFuture;
-
+```
let videos = use_future(|| async {
-+ TimeoutFuture::new(3_000).await; // 3 second delay
++ gloo_timers::future::TimeoutFuture::new(3_000).await; // 3 second delay
Request::get("/tutorial/data.json")
.send()
.await?
.json::>()
.await
-})?;
+
```
## Wrapping up
diff --git a/website/versioned_docs/version-0.23/tutorial/index.mdx b/website/versioned_docs/version-0.23/tutorial/index.mdx
index 6dffe1349eb..e929c59d5c9 100644
--- a/website/versioned_docs/version-0.23/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.23/tutorial/index.mdx
@@ -487,12 +487,16 @@ When choosing dependencies make sure they are `wasm32` compatible!
Otherwise you won't be able to run your application.
:::
-Update the `Video` struct to derive the `Deserialize` trait:
+Update the imports:
-```rust {2,4-5}
+```rust {2}
use yew::prelude::*;
+use serde::Deserialize;
-// ...
+```
+
+Update the `Video` struct to derive the `Deserialize` trait:
+
+```rust {2}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Deserialize)]
struct Video {
@@ -511,15 +515,20 @@ if hooks are unavailable, such as within struct components or standard functions
`use_future` suspends the component until the async operation completes, and `` shows a
fallback UI (e.g. a loading indicator) in the meantime.
-We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
-while the parent `App` wraps it in ``:
+Update the imports:
-```rust {3-4,6-10,12-43}
+```rust {3-4}
use yew::prelude::*;
use serde::Deserialize;
+use gloo_net::http::Request;
+use yew::suspense::use_future;
-// ..
+```
+
+We split the data fetching logic into a child component (`VideosFetcher`) that returns `HtmlResult`,
+while the parent `App` wraps it in ``:
+
+```rust {2-6,7-39}
+use yew::suspense::use_future;
+#[derive(Properties, PartialEq)]
+struct VideosFetchProps {
+ on_click: Callback,
@@ -562,8 +571,7 @@ use serde::Deserialize;
Now we will use the new component inside the App component.
-```rust {4-30,37-46}
-// ..
+```rust {3-30,37-46}
#[component]
fn App() -> Html {
- let videos = vec![
@@ -597,19 +605,20 @@ fn App() -> Html {
// ...
html! {
- <>
- { "RustConf Explorer" }
--
--
{ "Videos to watch" }
--
--
-+ {"Loading..."} }} >
-+
-+
- >
+- { "RustConf Explorer" }
+-
+-
{ "Videos to watch" }
+-
+-
++ <>
++ { "RustConf Explorer" }
++ {"Loading..."} }} >
++
++
++ >
}
}
```
@@ -625,9 +634,9 @@ To fix that, we need a proxy server. Luckily trunk provides that.
Update the following line:
-```rust {2-3}
-- let videos: Vec = Request::get("https://yew.rs/tutorial/data.json")
-+ let videos: Vec = Request::get("/tutorial/data.json")
+```rust {1-2}
+- Request::get("https://yew.rs/tutorial/data.json")
++ Request::get("/tutorial/data.json")
```
Now, rerun the server with the following command:
@@ -646,17 +655,15 @@ gloo-timers = { version = "0.3", features = ["futures"] }
```
Then add the delay inside the hook:
-```rust
-use gloo_timers::future::TimeoutFuture;
-
+```
let videos = use_future(|| async {
-+ TimeoutFuture::new(3_000).await; // 3 second delay
++ gloo_timers::future::TimeoutFuture::new(3_000).await; // 3 second delay
Request::get("/tutorial/data.json")
.send()
.await?
.json::>()
.await
-})?;
+
```
## Wrapping up
From 4f740af91a48fa1f785e5ff66f0e330647496dcb Mon Sep 17 00:00:00 2001
From: shan-shaji
Date: Wed, 29 Apr 2026 23:43:59 +0200
Subject: [PATCH 8/8] cleanup: run prettier format inside website directory
---
website/docs/tutorial/index.mdx | 1 +
website/versioned_docs/version-0.22/tutorial/index.mdx | 3 ++-
website/versioned_docs/version-0.23/tutorial/index.mdx | 3 ++-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/website/docs/tutorial/index.mdx b/website/docs/tutorial/index.mdx
index 674b6a1ce3e..30887995b09 100644
--- a/website/docs/tutorial/index.mdx
+++ b/website/docs/tutorial/index.mdx
@@ -644,6 +644,7 @@ artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add
```toml
gloo-timers = { version = "0.3", features = ["futures"] }
```
+
Then add the delay inside the hook:
```
diff --git a/website/versioned_docs/version-0.22/tutorial/index.mdx b/website/versioned_docs/version-0.22/tutorial/index.mdx
index 9da985f414f..3b9b1d3dbd2 100644
--- a/website/versioned_docs/version-0.22/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.22/tutorial/index.mdx
@@ -569,7 +569,7 @@ use yew::suspense::use_future;
+}
```
-Now we will use the new component inside the App component.
+Now we will use the new component inside the App component.
```rust {3-30,37-46}
#[component]
@@ -653,6 +653,7 @@ artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add
```toml
gloo-timers = { version = "0.3", features = ["futures"] }
```
+
Then add the delay inside the hook:
```
diff --git a/website/versioned_docs/version-0.23/tutorial/index.mdx b/website/versioned_docs/version-0.23/tutorial/index.mdx
index e929c59d5c9..ad2422158af 100644
--- a/website/versioned_docs/version-0.23/tutorial/index.mdx
+++ b/website/versioned_docs/version-0.23/tutorial/index.mdx
@@ -569,7 +569,7 @@ use yew::suspense::use_future;
+}
```
-Now we will use the new component inside the App component.
+Now we will use the new component inside the App component.
```rust {3-30,37-46}
#[component]
@@ -653,6 +653,7 @@ artificial delay inside the `use_future` hook using `TimeoutFuture`. First, add
```toml
gloo-timers = { version = "0.3", features = ["futures"] }
```
+
Then add the delay inside the hook:
```