Yew漫画阅读器:切换路由时如何中止Pending GET请求?
Yew漫画阅读器:路由切换时中止未完成的缩略图请求
我正在开发一款基于Yew的漫画阅读器,首页是带缩略图的书架,点击缩略图可进入书籍内容页。现在碰到个问题:缩略图还没加载完就点进内容页,页面得等所有pending的缩略图请求都完成才开始加载书籍内容。想在首页组件销毁(切换到内容页)时中止所有未完成的缩略图请求,让内容页立刻开始加载。
解决方案一:手动用AbortController中止请求
Yew的Request支持通过AbortController中止请求,利用组件use_effect的清理函数就能实现组件卸载时自动中止请求。
给Book组件添加请求中止逻辑
修改Book组件,用AbortController管理缩略图请求,组件卸载时自动触发中止:
#[function_component] fn Book(props: BookProps) -> Html { let thumbnail = use_state(|| None::<String>); let abort_controller = use_state(|| AbortController::new()); { let thumbnail = thumbnail.clone(); let abort_controller = abort_controller.clone(); let book_name = props.name.clone(); use_effect_with((), move |_| { let thumbnail = thumbnail.clone(); let abort_controller = abort_controller.clone(); wasm_bindgen_futures::spawn_local(async move { let url = format!("{}/books/{}/thumbnail", BACKEND_URL, book_name); let request = Request::get(&url) .signal(abort_controller.signal()) // 绑定中止信号 .body(()) .unwrap(); match Request::send(&request).await { Ok(response) => { if response.ok() { let img_url = response.text().await.unwrap(); thumbnail.set(Some(img_url)); } }, Err(_) => { // 请求被中止,无需额外处理 } } }); // 组件卸载时执行清理函数,中止请求 move || { abort_controller.abort(); } }); } // 点击跳转逻辑 let navigate = use_navigate(); let onclick = { let navigate = navigate.clone(); let book_name = props.name.clone(); Callback::from(move |_| { navigate.to(&Route::BookContent { name: book_name.clone() }); }) }; html! { <div onclick={onclick}> { if let Some(img) = *thumbnail { <img src={img} alt={&props.name} /> } else { <div>{ "加载中..." }</div> } } </div> } }
可选:在BookShelf层面统一管理请求
如果想在书架组件销毁时一次性中止所有子组件的请求,可以用Context传递AbortController:
- 定义Context:
#[derive(Clone, PartialEq)] struct RequestAbortContext { abort_controller: AbortController, } static REQUEST_ABORT_CONTEXT: Context<RequestAbortContext> = Context::new();
- 在
BookShelf中创建并提供Context:
#[styled_component] fn BookShelf() -> Html { let books = use_state(|| vec![]); let abort_controller = use_state(|| AbortController::new()); // 获取书籍列表的原有逻辑... // 书架组件卸载时中止所有请求 use_effect_with((), move |_| { let abort_controller = abort_controller.clone(); move || { abort_controller.abort(); } }); html! { <REQUEST_ABORT_CONTEXT.Provider value={RequestAbortContext { abort_controller: (*abort_controller).clone() }}> {/* 原有书籍列表渲染逻辑 */} </REQUEST_ABORT_CONTEXT.Provider> } }
- 在
Book组件中使用Context:
#[function_component] fn Book(props: BookProps) -> Html { let ctx = use_context::<RequestAbortContext>().unwrap(); // 后续请求绑定ctx.abort_controller.signal()即可 }
解决方案二:用Yew Query替代手动请求管理
Yew Query是Yew生态里类似React Query的库,内置请求中止、缓存等功能,完全适配组件生命周期,和你提到的Theo视频思路一致。
1. 添加依赖
在Cargo.toml中添加:
yew-query = "0.2"
2. 用use_query获取缩略图
修改Book组件,无需手动处理请求中止,组件卸载时Yew Query会自动完成:
use yew_query::prelude::*; #[function_component] fn Book(props: BookProps) -> Html { let query_client = use_query_client(); let book_name = props.name.clone(); // 定义查询,组件卸载时自动中止未完成请求 let thumbnail_query = use_query( QueryKey::from(vec!["thumbnail", &book_name]), move |_| async move { let url = format!("{}/books/{}/thumbnail", BACKEND_URL, book_name); let response = Request::get(&url) .send() .await? .text() .await?; Ok(response) }, QueryOptions::default(), ); // 点击跳转逻辑和之前一致... html! { <div onclick={onclick}> { match thumbnail_query.state() { QueryState::Loading => html! { <div>{ "加载中..." }</div> }, QueryState::Success(img) => html! { <img src={img} alt={&props.name} /> }, QueryState::Error(_) => html! { <div>{ "缩略图加载失败" }</div> }, } } </div> } }
关于Context + use_location/use_route的思路
这个思路是可行的:可以用Context维护当前路由状态,在Book组件里监听路由变化,当路由离开首页时中止请求。但相比前两种方案,需要手动维护路由监听和请求的关联,复杂度更高,不如直接用AbortController的清理函数或Yew Query来得简洁。
内容的提问来源于stack exchange,提问作者Austin
相关产品推荐
相关产品推荐

