mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Resume Suspension upon unmount (#2874)
* Restore a behaviour of destroy upon unmount. * Add a test. * Fix CI. * Fix CI.
This commit is contained in:
parent
beb0157c48
commit
ce70e4c1fb
@ -297,6 +297,17 @@ impl ComponentState {
|
||||
.downcast_ref::<CompStateInner<COMP>>()
|
||||
.map(|m| &m.component)
|
||||
}
|
||||
|
||||
fn resume_existing_suspension(&mut self) {
|
||||
if let Some(m) = self.suspension.take() {
|
||||
let comp_scope = self.inner.any_scope();
|
||||
|
||||
let suspense_scope = comp_scope.find_parent_scope::<BaseSuspense>().unwrap();
|
||||
let suspense = suspense_scope.get_component().unwrap();
|
||||
|
||||
suspense.resume(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CreateRunner<COMP: BaseComponent> {
|
||||
@ -370,6 +381,7 @@ impl ComponentState {
|
||||
)]
|
||||
fn destroy(mut self, parent_to_detach: bool) {
|
||||
self.inner.destroy();
|
||||
self.resume_existing_suspension();
|
||||
|
||||
match self.render_state {
|
||||
#[cfg(feature = "csr")]
|
||||
@ -479,14 +491,7 @@ impl ComponentState {
|
||||
fn commit_render(&mut self, shared_state: &Shared<Option<ComponentState>>, new_root: Html) {
|
||||
// Currently not suspended, we remove any previous suspension and update
|
||||
// normally.
|
||||
if let Some(m) = self.suspension.take() {
|
||||
let comp_scope = self.inner.any_scope();
|
||||
|
||||
let suspense_scope = comp_scope.find_parent_scope::<BaseSuspense>().unwrap();
|
||||
let suspense = suspense_scope.get_component().unwrap();
|
||||
|
||||
suspense.resume(m);
|
||||
}
|
||||
self.resume_existing_suspension();
|
||||
|
||||
match self.render_state {
|
||||
#[cfg(feature = "csr")]
|
||||
|
||||
@ -8,9 +8,9 @@ use std::time::Duration;
|
||||
|
||||
use common::obtain_result;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use wasm_bindgen_test::*;
|
||||
use web_sys::{HtmlElement, HtmlTextAreaElement};
|
||||
use yew::platform::spawn_local;
|
||||
use yew::platform::time::sleep;
|
||||
use yew::prelude::*;
|
||||
use yew::suspense::{use_future, use_future_with_deps, Suspension, SuspensionResult};
|
||||
@ -684,3 +684,53 @@ async fn use_suspending_future_with_deps_works() {
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), r#"<div>42</div>"#);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn test_suspend_forever() {
|
||||
/// A component that its suspension never resumes.
|
||||
/// We test that this can be used with to trigger a suspension and unsuspend upon unmount.
|
||||
#[function_component]
|
||||
fn SuspendForever() -> HtmlResult {
|
||||
let (s, handle) = Suspension::new();
|
||||
use_state(move || handle);
|
||||
Err(s.into())
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn App() -> Html {
|
||||
let page = use_state(|| 1);
|
||||
|
||||
{
|
||||
let page_setter = page.setter();
|
||||
use_effect_with_deps(
|
||||
move |_| {
|
||||
spawn_local(async move {
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
page_setter.set(2);
|
||||
});
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
|
||||
let content = if *page == 1 {
|
||||
html! { <SuspendForever /> }
|
||||
} else {
|
||||
html! { <div id="result">{"OK"}</div> }
|
||||
};
|
||||
|
||||
html! {
|
||||
<Suspense fallback={html! {<div>{"Loading..."}</div>}}>
|
||||
{content}
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
||||
yew::Renderer::<App>::with_root(gloo::utils::document().get_element_by_id("output").unwrap())
|
||||
.render();
|
||||
|
||||
sleep(Duration::from_millis(1500)).await;
|
||||
|
||||
let result = obtain_result();
|
||||
assert_eq!(result.as_str(), r#"OK"#);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user