首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在更新状态的yew struct组件中使用wasm_bindgen_futures发出HTTP请求

如何在更新状态的yew struct组件中使用wasm_bindgen_futures发出HTTP请求
EN

Stack Overflow用户
提问于 2022-08-18 19:53:32
回答 1查看 327关注 0票数 1

我有一个yew struct组件,它应该向api发出一个get请求,然后呈现项目列表。我试图在组件的呈现方法中执行请求,并且遇到了无法在wasm_bindgen_future中使用对self的引用的终身问题。我必须使用wasm_bindgen_future来执行异步api请求。这是代码(大致)

代码语言:javascript
复制
pub struct ViewLessonPlans {
    lesson_plans: Vec<LessonPlan>,
    loading_condition: ComponentLoadingStage
}

impl Component for ViewLessonPlans {
    type Message = ();
    type Properties = ();

    fn create(ctx: &Context<Self>) -> Self {
        Self {
            lesson_plans: vec![],
            loading_condition: ComponentLoadingStage::Loading
        }
    }

    fn view(&self, ctx: &Context<Self>) -> Html {

        match self.loading_condition {
            ComponentLoadingStage::Loading => {
                html! { <h1>{"Lesson Plans Loading"}</h1>}
            },
            ComponentLoadingStage::Success => {
                self.lesson_plans.iter().map(|lp| {
                    html! { <ViewLessonPlan lesson_plan={lp.clone()} /> }
                }).collect::<Html>()
            },
            ComponentLoadingStage::Error => {
                html! { <h1>{ "There was an error loading the lesson plans!" }</h1>}
            },
        }
    }

    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
        if first_render {
            wasm_bindgen_futures::spawn_local(async move {
                match get_lesson_plans().await {
                    Ok(lesson_plans) => {
                        self.lesson_plans = lesson_plans.iter().map(|(_id, lp)| {
                            lp.clone()
                        }).collect();
                        self.loading_condition = ComponentLoadingStage::Success;
                    },
                    Err(_) => {
                        self.loading_condition = ComponentLoadingStage::Error;
                    },
                }
            });
        }
    }
}

以及产生的错误

代码语言:javascript
复制
`self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
...is used here...rustcE0759

我如何发出这个api请求并使用响应来更新self?

编辑:作为参考,这是我想要的功能的function_component版本。令人烦恼的是,它在刷新时简短地显示错误大小写,不确定原因。我对ComponentLoadingStage做了一些重构,这样成功变体就可以简单地包含api响应内容,从而使事情变得更简单。

代码语言:javascript
复制
#[function_component(ViewLessonPlans)]
pub fn view_lesson_plans() -> Html {
    // Setup the state
    let state_init: UseStateHandle<ComponentLoadingStage<Vec<LessonPlan>>> =
        use_state(|| ComponentLoadingStage::Loading);
    let state = state_init.clone();

    // Perform the API request
    wasm_bindgen_futures::spawn_local(async move {
        match get_lesson_plans().await {
            Ok(lesson_plans) => {
                state.set(ComponentLoadingStage::Success(
                    lesson_plans.iter().map(|(_id, lp)| lp.clone()).collect(),
                ));
            }
            Err(_) => {
                state.set(ComponentLoadingStage::Error);
            }
        }
    });

    // Return the view
    match (*state_init).clone() {
        ComponentLoadingStage::Loading => {
            html! { <h1>{"Lesson Plans Loading"}</h1>}
        }
        ComponentLoadingStage::Success(lesson_plans) => lesson_plans
            .iter()
            .map(|lp| {
                html! { <ViewLessonPlan lesson_plan={lp.clone()} /> }
            })
            .collect::<Html>(),
        ComponentLoadingStage::Error => {
            html! { <h1>{ "There was an error loading the lesson plans!" }</h1>}
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-19 00:02:08

在创建异步块时,可能会将其中的任何内容抛给另一个线程,或者在两年内调用。这就是为什么铁锈不允许你移动裁判,而不是静态的。

spawn_local()函数具体声明:

未来必须是‘静态的,因为它将被安排在后台运行,并且不能包含任何堆栈引用。

因此,你不能使用可变的引用自我,但有一种方式,我的朋友!

Yew知道,在UI的上下文中,您需要一种方式在未知的情况下向自己发送信息,比如单击按钮。

有Yew允许您创建的更新方法,它们接受消息,您可以对这些消息做出反应。

因此,您需要做的是创建一个链接,将其移动到异步块,调用get_lesson_plans()方法,并使用该链接发送消息。然后,您将在update方法中接收结果,该方法可以访问对self的可变引用。

看起来是这样的:

代码语言:javascript
复制
impl Component for ViewLessonPlans {
    type Message = Result<..., ...>; // plug return type of get_lesson_plans()
    type Properties = ();

    fn create(ctx: &Context<Self>) -> Self {
        Self {
            lesson_plans: vec![],
            loading_condition: ComponentLoadingStage::Loading
        }
    }

    fn view(&self, ctx: &Context<Self>) -> Html {

        match self.loading_condition {
            ComponentLoadingStage::Loading => {
                html! { <h1>{"Lesson Plans Loading"}</h1>}
            },
            ComponentLoadingStage::Success => {
                self.lesson_plans.iter().map(|lp| {
                    html! { <ViewLessonPlan lesson_plan={lp.clone()} /> }
                }).collect::<Html>()
            },
            ComponentLoadingStage::Error => {
                html! { <h1>{ "There was an error loading the lesson plans!" }</h1>}
            },
        }
    }

    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
        if first_render {
            let link = ctx.link().clone();
            wasm_bindgen_futures::spawn_local(async move {
                let result = get_lesson_plans().await;
                link.send_message(result);
            });
        }
    }

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            Ok(lesson_plans) => {
                self.lesson_plans = lesson_plans.iter().map(|(_id, lp)| {
                    lp.clone()
                }).collect();
                self.loading_condition = ComponentLoadingStage::Success;
            },
            Err(_) => {
                self.loading_condition = ComponentLoadingStage::Error;
            },
        }
        true
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73408722

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档