implement suspense using simpler approach
This commit is contained in:
5 files changed
+27
-83
No files matched your search
@@ -40,6 +40,7 @@ tokio = { workspace = true, features = ["full"] }
|
|||||||
dioxus = { workspace = true }
|
dioxus = { workspace = true }
|
||||||
pretty_assertions = "1.3.0"
|
pretty_assertions = "1.3.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
dioxus-ssr = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ impl VirtualDom {
|
|||||||
|
|
||||||
if scope.suspended.get() {
|
if scope.suspended.get() {
|
||||||
self.suspended_scopes.insert(scope.id);
|
self.suspended_scopes.insert(scope.id);
|
||||||
|
} else if !self.suspended_scopes.is_empty() {
|
||||||
|
_ = self.suspended_scopes.remove(&scope.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rebind the lifetime now that its stored internally
|
// rebind the lifetime now that its stored internally
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ impl<'src> ScopeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Mark this component as suspended and then return None
|
/// Mark this component as suspended and then return None
|
||||||
pub fn suspend(&self) -> Option<()> {
|
pub fn suspend(&self) -> Option<Element> {
|
||||||
self.suspended.set(true);
|
self.suspended.set(true);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -572,10 +572,12 @@ impl VirtualDom {
|
|||||||
pub async fn wait_for_suspense(&mut self) {
|
pub async fn wait_for_suspense(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
if self.suspended_scopes.is_empty() {
|
if self.suspended_scopes.is_empty() {
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.wait_for_work().await;
|
self.wait_for_work().await;
|
||||||
|
|
||||||
|
_ = self.render_immediate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,103 +1,42 @@
|
|||||||
use dioxus::core::ElementId;
|
|
||||||
use dioxus::core::Mutation::*;
|
use dioxus::core::Mutation::*;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use std::future::IntoFuture;
|
use std::future::IntoFuture;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn it_works() {
|
async fn it_works() {
|
||||||
// wait just a moment, not enough time for the boundary to resolve
|
// wait just a moment, not enough time for the boundary to resolve
|
||||||
|
|
||||||
tokio::runtime::Builder::new_current_thread()
|
let mut dom = VirtualDom::new(app);
|
||||||
.enable_time()
|
_ = dom.rebuild();
|
||||||
.build()
|
dom.wait_for_suspense().await;
|
||||||
.unwrap()
|
let out = dioxus_ssr::pre_render(&dom);
|
||||||
.block_on(async {
|
|
||||||
let mut dom = VirtualDom::new(app);
|
|
||||||
|
|
||||||
{
|
assert_eq!(out, "<div>Waiting for... child</div>");
|
||||||
let mutations = dom.rebuild().santize();
|
|
||||||
|
|
||||||
// We should at least get the top-level template in before pausing for the children
|
dbg!(out);
|
||||||
// note: we dont test template edits anymore
|
|
||||||
// assert_eq!(
|
|
||||||
// mutations.templates,
|
|
||||||
// [
|
|
||||||
// CreateElement { name: "div" },
|
|
||||||
// CreateStaticText { value: "Waiting for child..." },
|
|
||||||
// CreateStaticPlaceholder,
|
|
||||||
// AppendChildren { m: 2 },
|
|
||||||
// SaveTemplate { name: "template", m: 1 }
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// And we should load it in and assign the placeholder properly
|
|
||||||
assert_eq!(
|
|
||||||
mutations.edits,
|
|
||||||
[
|
|
||||||
LoadTemplate { name: "template", index: 0, id: ElementId(1) },
|
|
||||||
// hmmmmmmmmm.... with suspense how do we guarantee that IDs increase linearly?
|
|
||||||
// can we even?
|
|
||||||
AssignId { path: &[1], id: ElementId(3) },
|
|
||||||
AppendChildren { m: 1, id: ElementId(0) },
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.wait_for_work().await;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div {
|
div {
|
||||||
"Waiting for child..."
|
"Waiting for... "
|
||||||
suspense_boundary {}
|
suspended_child {}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suspense_boundary(cx: Scope) -> Element {
|
fn suspended_child(cx: Scope) -> Element {
|
||||||
todo!()
|
let mut val = use_state(cx, || 0);
|
||||||
// cx.use_hook(|| {
|
|
||||||
// cx.provide_context(Rc::new(SuspenseContext::new(cx.scope_id())));
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Ensure the right types are found
|
if **val < 3 {
|
||||||
// cx.has_context::<Rc<SuspenseContext>>().unwrap();
|
let mut val = val.clone();
|
||||||
|
cx.spawn(async move {
|
||||||
|
val += 1;
|
||||||
|
});
|
||||||
|
return cx.suspend()?;
|
||||||
|
}
|
||||||
|
|
||||||
// cx.render(rsx!(async_child {}))
|
render!("child")
|
||||||
}
|
|
||||||
|
|
||||||
fn async_child(cx: Scope<'_>) -> Element {
|
|
||||||
todo!()
|
|
||||||
// use_future!(cx, || tokio::time::sleep(Duration::from_millis(10))).await;
|
|
||||||
// cx.render(rsx!(async_text {}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn async_text(cx: Scope<'_>) -> Element {
|
|
||||||
todo!()
|
|
||||||
// let username = use_future!(cx, || async {
|
|
||||||
// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
|
||||||
// "async child 1"
|
|
||||||
// });
|
|
||||||
|
|
||||||
// let age = use_future!(cx, || async {
|
|
||||||
// tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
|
||||||
// 1234
|
|
||||||
// });
|
|
||||||
|
|
||||||
// let (_user, _age) = use_future!(cx, || async {
|
|
||||||
// tokio::join!(
|
|
||||||
// tokio::time::sleep(std::time::Duration::from_secs(1)),
|
|
||||||
// tokio::time::sleep(std::time::Duration::from_secs(2))
|
|
||||||
// );
|
|
||||||
// ("async child 1", 1234)
|
|
||||||
// })
|
|
||||||
// .await;
|
|
||||||
|
|
||||||
// let (username, age) = tokio::join!(username.into_future(), age.into_future());
|
|
||||||
|
|
||||||
// cx.render(rsx!( div { "Hello! {username}, you are {age}, {_user} {_age}" } ))
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user