Add examples of canceling in-flight requests (issue #32) and filter against empty IDs to avoid extra requests (issue #123)

This commit is contained in:
Greg Johnston 2022-11-26 15:29:46 -05:00
parent fdd07aafb7
commit ed24e47c1d
5 changed files with 31 additions and 6 deletions

View file

@ -26,6 +26,7 @@ serde_json = "1"
gloo-net = { version = "0.2", features = ["http"] }
reqwest = { version = "0.11", features = ["json"] }
# openssl = { version = "0.10", features = ["v110"] }
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
[features]
default = ["csr"]

View file

@ -1,4 +1,4 @@
use leptos::Serializable;
use leptos::{on_cleanup, Scope, Serializable};
use serde::{Deserialize, Serialize};
pub fn story(path: &str) -> String {
@ -10,11 +10,15 @@ pub fn user(path: &str) -> String {
}
#[cfg(not(feature = "ssr"))]
pub async fn fetch_api<T>(path: &str) -> Option<T>
pub async fn fetch_api<T>(cx: Scope, path: &str) -> Option<T>
where
T: Serializable,
{
let abort_controller = web_sys::AbortController::new().ok();
let abort_signal = abort_controller.as_ref().map(|a| a.signal());
let json = gloo_net::http::Request::get(path)
.abort_signal(abort_signal.as_ref())
.send()
.await
.map_err(|e| log::error!("{e}"))
@ -22,11 +26,19 @@ where
.text()
.await
.ok()?;
// abort in-flight requests if the Scope is disposed
// i.e., if we've navigated away from this page
on_cleanup(cx, move || {
if let Some(abort_controller) = abort_controller {
abort_controller.abort()
}
});
T::from_json(&json).ok()
}
#[cfg(feature = "ssr")]
pub async fn fetch_api<T>(path: &str) -> Option<T>
pub async fn fetch_api<T>(cx: Scope, path: &str) -> Option<T>
where
T: Serializable,
{

View file

@ -32,7 +32,7 @@ pub fn Stories(cx: Scope) -> Element {
move || (page(), story_type()),
move |(page, story_type)| async move {
let path = format!("{}?page={}", category(&story_type), page);
api::fetch_api::<Vec<api::Story>>(&api::story(&path)).await
api::fetch_api::<Vec<api::Story>>(cx, &api::story(&path)).await
},
);

View file

@ -8,7 +8,13 @@ pub fn Story(cx: Scope) -> Element {
let story = create_resource(
cx,
move || params().get("id").cloned().unwrap_or_default(),
move |id| async move { api::fetch_api::<api::Story>(&api::story(&format!("item/{id}"))).await },
move |id| async move {
if id.is_empty() {
None
} else {
api::fetch_api::<api::Story>(cx, &api::story(&format!("item/{id}"))).await
}
},
);
view! { cx,

View file

@ -8,7 +8,13 @@ pub fn User(cx: Scope) -> Element {
let user = create_resource(
cx,
move || params().get("id").cloned().unwrap_or_default(),
move |id| async move { api::fetch_api::<User>(&api::user(&id)).await },
move |id| async move {
if id.is_empty() {
None
} else {
api::fetch_api::<User>(cx, &api::user(&id)).await
}
},
);
view! { cx,
<div class="user-view">