I have a yew struct component that should make a get request to the api and then render the list of items. I'm trying to perform the request inside the render method of the component and I'm running into lifetime issues where I can't use the reference to self within the wasm_bindgen_future. I have to use the wasm_bindgen_future in order to execute the async api request. Here is the code (roughly)
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;
},
}
});
}
}
}
and the generated error
`self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
...is used here...rustcE0759
How can I make this api request and use the response to update self?
Edit: For reference, this is my function_component version of the desired functionality. Annoyingly it displays the Error case briefly on refresh, not sure why. I've done a little refactoring of ComponentLoadingStage so that the success variant can simply contain the api response content to make things simpler.
#[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>}
}
}
}