HI, I'm trying to write a little web app, I just copy the counter example of yew and add a fetching action, code as bellow:
use failure::Error;
use serde_derive::{Deserialize, Serialize};
use stdweb::web::Date;
use yew::format::{Json, Nothing};
use yew::prelude::*;
use yew::services::ConsoleService;
use yew::services::{
fetch::{Request, Response},
FetchService,
};
use yew::{html, html_impl};
// {
// "data": {
// "id": 1,
// "first_name": "George",
// "last_name": "Bluth",
// "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
// }
// }
#[derive(Serialize, Deserialize, Debug)]
pub struct User {
id: usize,
first_name: String,
last_name: String,
avatar: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Data {
data: User,
}
pub struct Model {
console: ConsoleService,
fetch: FetchService,
link: ComponentLink<Model>,
value: i64,
user: Option<User>,
}
pub enum Msg {
Increment,
Decrement,
Bulk(Vec<Msg>),
FetchUser(usize),
FetchReady(User),
Ignore,
}
impl Component for Model {
type Message = Msg;
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
Model {
console: ConsoleService::new(),
fetch: FetchService::new(),
link,
value: 0,
user: None,
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::Increment => {
self.value = self.value + 1;
self.console.log("plus one");
}
Msg::Decrement => {
self.value = self.value - 1;
self.console.log("minus one");
}
Msg::Bulk(list) => for msg in list {
self.update(msg);
self.console.log("Bulk action");
},
Msg::FetchUser(id) => {
let url = format!("https://reqres.in/api/users/{}", id);
let request = Request::get(&url)
.body(Nothing)
.expect("Failed to build request.");
let callback =
self.link
.send_back(move |response: Response<Json<Result<Data, Error>>>| {
let (meta, Json(data)) = response.into_parts();
// let info = format!("META: {:?}, {:?}", meta, data);
if meta.status.is_success() {
if let Ok(d) = data {
Msg::FetchReady(d.data)
} else {
Msg::Ignore // FIXME: Handle this error accordingly.
}
} else {
Msg::Ignore // FIXME: Handle this error accordingly.
}
});
self.fetch.fetch(request, callback);
self.console.log("request start.");
}
Msg::FetchReady(user) => {
self.console.log("request ok.");
self.user = Some(user);
}
Msg::Ignore => {
self.console.log("request error.");
}
}
true
}
}
impl Renderable<Model> for Model {
fn view(&self) -> Html<Self> {
html! {
<div>
<nav class="menu",>
<button onclick=|_| Msg::Increment,>{ "Increment" }</button>
<button onclick=|_| Msg::Decrement,>{ "Decrement" }</button>
<button onclick=|_| Msg::Bulk(vec![Msg::Increment, Msg::Increment]),>{ "Increment Twice" }</button>
<button onclick=|_| Msg::FetchUser(1),>{ "鑾峰彇鐢ㄦ埛" }</button>
</nav>
<p>{ self.value }</p>
<p>{ self.user.as_ref().map(|u| u.first_name.clone()).unwrap_or("".into())}</p>
<p>{ Date::new().to_string() }</p>
</div>
}
}
}
Seams FetchService is not work.


I don't known if this is a bug of framework itself, but how to fix it?
ps: using command is cargo web start --target=wasm32-unknown-unknown --release
The fetch service both cancels requests and stops handling any responses when the handle (FetchTask) returned by self.fetch.fetch(request, callback) is dropped (here it goes out of scope instantly).
You need to store the reference to the fetch task for the duration of the request in for example the Model.
It works! Thanks! @davidkna
Most helpful comment
The fetch service both cancels requests and stops handling any responses when the handle (
FetchTask) returned byself.fetch.fetch(request, callback)is dropped (here it goes out of scope instantly).You need to store the reference to the fetch task for the duration of the request in for example the
Model.