从外部中止 `wasm_bindgen_futures::spawn_local` 回调

问题描述 投票:0回答:1

我正在构建一个 Yew 漫画阅读器应用程序。主页是一个包含缩略图的书架,单击缩略图会将我带到呈现书籍页面的页面。

fn switch(routes: Route) -> Html {
    match routes {
        Route::Home => html! {
            <>
                <h1>{ "Books" }</h1>
                <BookShelf />
            </>
        },
        Route::BookContent { name } => html! {
            <div>
                <BookContent name={name} />
            </div>
        },
        Route::NotFound => html! { <div>{ "You sure that book exist?" }</div> },
    }
}

#[function_component]
fn App() -> Html {
    html! {
        <HashRouter>
            <Switch<Route> render={switch} />
        </HashRouter>
    }
}

BookShelf
获取我拥有的书籍列表,单独获取缩略图以在两列中呈现。

#[styled_component]
fn BookShelf() -> Html {
    let books = use_state(|| vec![]);
    {
        let books = books.clone();
        use_effect_with((), move |_| {
            let books = books.clone();
            wasm_bindgen_futures::spawn_local(async move {
                let url = format!("{}/books", BACKEND_URL);
                let fetched_books: Vec<String> = Request::get(&url)
                    .send()
                    .await
                    .unwrap()
                    .json()
                    .await
                    .unwrap();
                books.set(fetched_books);
            });
        })
    }

    html! {
        <>
            {
                for books.chunks(2).map(|books| html! {
                    <div class={css!("display:flex;")}>
                        {
                            books.iter().map(|book| html! {
                                <div class={css!("flex:50%;")}>
                                    <Book name={book.clone()}/>
                                </div>
                            }).collect::<Html>()
                        }
                    </div>
                })
            }
        </>
    }
}

Book
组件实际上使用
use_effect_with()
获取缩略图。单击时,它还会将路线切换到
Route::BookContent

BookContent
BookShelf
类似,只是它在同一列中获取和渲染图像。

页面的当前行为是,当我在获取和加载所有缩略图之前单击缩略图时,它会转到

BookContent
页面,但它会等待所有挂起的缩略图
GET
请求完成,然后再获取图书内容。

如何在

Route::Home
组件消失后中止所有待处理的获取请求(也称为单击缩略图转到
Route::BookContent
),以便我可以立即开始获取图书内容?

编辑

我刚刚看到 Theo 的视频“你现在比以往任何时候都更需要 React Query”,其中提到你可以向

useQuery
发送信号并中止查询。我想这可能是我需要的,如果路线改变,提前返回回调。可能使用上下文和
use_location
/
use_route
的组合?

rust callback single-page-application wasm-bindgen yew
1个回答
0
投票

所以实际上我应该中止的 future 是

gloo_net::http::Request
而不是
wasm_bindgen_futures::spwan_local
,因为 wasm future 会立即调度它所渲染的内容,而正在等待的是
Request
。幸运的是,通过设置
gloo_net::http::Request
AbortSignal
中有一个中止机制。

利用

use_effect_with()
在组件被销毁时调用其返回值进行清理这一事实,我们可以在
Request
组件超出范围时中止
Image

use gloo_net::http::Request;
use web_sys::AbortController;

#[derive(Properties, PartialEq)]
struct ImageProperties {
    url: String,
}

#[function_component]
fn Image(props: &ImageProperties) -> Html {
    let image = use_state(|| String::new());
    {
        let image = image.clone();
        let url = props.url.clone();
        let controller = AbortController::new().unwrap();
        let signal = controller.signal();
        use_effect_with((), move |_| {
            let _ = wasm_bindgen_futures::spawn_local(async move {
                let res = Request::get(&url)
                    .abort_signal(Some(&signal))
                    .send()
                    .await
                    .unwrap();
                let type_ = res.headers().get("Content-Type").unwrap();
                let bytes = res.binary().await.unwrap();
                let data = b64.encode(bytes);
                image.set(format!("data:{};base64,{}", type_, data));
            });

            move || {
                controller.abort();
            }
        });
    }

    html! {
        <img
            src={(*image).clone()}
            alt={"loading"}
            style="height:auto;width:100%;object-fit:inherit"
        />
    }
}

请注意,如果您使用

渲染图像
html! {
    html! {
        <img src={url} alt={"loading"}/>
    }
}

即使组件被销毁,由

GET
标签调度的
img
请求也不会被中止。

© www.soinside.com 2019 - 2024. All rights reserved.