Yew: FetchService not work.

Created on 5 Sep 2018  路  2Comments  路  Source: yewstack/yew

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.
screen shot 2018-09-05 at 14 14 58
screen shot 2018-09-05 at 14 15 27

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

Most helpful comment

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.

All 2 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kellytk picture kellytk  路  4Comments

alun picture alun  路  4Comments

agausmann picture agausmann  路  3Comments

wldcordeiro picture wldcordeiro  路  4Comments

thienpow picture thienpow  路  3Comments