mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
fix: require Suspend::new()
to ensure the Future
is properly scoped at creation time, not at render time
This commit is contained in:
parent
b24ae7a5e3
commit
93e6456e19
3 changed files with 36 additions and 18 deletions
|
@ -204,11 +204,11 @@ mod view_implementations {
|
|||
type State = RenderEffectState<SuspendState<T, R>>;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
(move || Suspend(async move { self.await })).build()
|
||||
(move || Suspend::new(async move { self.await })).build()
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
(move || Suspend(async move { self.await })).rebuild(state)
|
||||
(move || Suspend::new(async move { self.await })).rebuild(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ mod view_implementations {
|
|||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
(move || Suspend(async move { self.await })).add_any_attr(attr)
|
||||
(move || Suspend::new(async move { self.await })).add_any_attr(attr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ mod view_implementations {
|
|||
}
|
||||
|
||||
fn resolve(self) -> impl Future<Output = Self::AsyncOutput> + Send {
|
||||
(move || Suspend(async move { self.await })).resolve()
|
||||
(move || Suspend::new(async move { self.await })).resolve()
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
|
@ -267,7 +267,7 @@ mod view_implementations {
|
|||
position: &mut Position,
|
||||
escape: bool,
|
||||
) {
|
||||
(move || Suspend(async move { self.await }))
|
||||
(move || Suspend::new(async move { self.await }))
|
||||
.to_html_with_buf(buf, position, escape);
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ mod view_implementations {
|
|||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
(move || Suspend(async move { self.await }))
|
||||
(move || Suspend::new(async move { self.await }))
|
||||
.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape);
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ mod view_implementations {
|
|||
cursor: &Cursor<R>,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
(move || Suspend(async move { self.await }))
|
||||
(move || Suspend::new(async move { self.await }))
|
||||
.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,13 @@ use std::{
|
|||
pin_project! {
|
||||
/// A [`Future`] wrapper that sets the [`Owner`] and [`Observer`] before polling the inner
|
||||
/// `Future`.
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct ScopedFuture<Fut> {
|
||||
owner: Option<Owner>,
|
||||
observer: Option<AnySubscriber>,
|
||||
pub owner: Option<Owner>,
|
||||
pub observer: Option<AnySubscriber>,
|
||||
#[pin]
|
||||
fut: Fut,
|
||||
pub fut: Fut,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,14 @@ use std::{cell::RefCell, fmt::Debug, future::Future, pin::Pin, rc::Rc};
|
|||
|
||||
/// A suspended `Future`, which can be used in the view.
|
||||
#[derive(Clone)]
|
||||
pub struct Suspend<Fut>(pub Fut);
|
||||
pub struct Suspend<Fut>(pub ScopedFuture<Fut>); // TODO probably shouldn't be pub
|
||||
|
||||
impl<Fut> Suspend<Fut> {
|
||||
/// Creates a new suspended view.
|
||||
pub fn new(fut: Fut) -> Self {
|
||||
Self(ScopedFuture::new(fut))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Fut> Debug for Suspend<Fut> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -69,7 +76,7 @@ where
|
|||
// poll the future once immediately
|
||||
// if it's already available, start in the ready state
|
||||
// otherwise, start with the fallback
|
||||
let mut fut = Box::pin(ScopedFuture::new(self.0));
|
||||
let mut fut = Box::pin(self.0);
|
||||
let initial = fut.as_mut().now_or_never();
|
||||
let initially_pending = initial.is_none();
|
||||
let inner = Rc::new(RefCell::new(initial.build()));
|
||||
|
@ -96,7 +103,7 @@ where
|
|||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
// get a unique ID if there's a SuspenseContext
|
||||
let fut = ScopedFuture::new(self.0);
|
||||
let fut = self.0;
|
||||
let id = use_context::<SuspenseContext>().map(|sc| sc.task_id());
|
||||
|
||||
// spawn the future, and rebuild the state when it resolves
|
||||
|
@ -137,10 +144,19 @@ where
|
|||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let attr = attr.into_cloneable_owned();
|
||||
Suspend(Box::pin(async move {
|
||||
let this = self.0.await;
|
||||
this.add_any_attr(attr)
|
||||
}))
|
||||
let ScopedFuture {
|
||||
owner,
|
||||
observer,
|
||||
fut,
|
||||
} = self.0;
|
||||
Suspend(ScopedFuture {
|
||||
owner,
|
||||
observer,
|
||||
fut: Box::pin(async move {
|
||||
let this = fut.await;
|
||||
this.add_any_attr(attr)
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +250,7 @@ where
|
|||
// poll the future once immediately
|
||||
// if it's already available, start in the ready state
|
||||
// otherwise, start with the fallback
|
||||
let mut fut = Box::pin(ScopedFuture::new(self.0));
|
||||
let mut fut = Box::pin(self.0);
|
||||
let initial = fut.as_mut().now_or_never();
|
||||
let initially_pending = initial.is_none();
|
||||
let inner = Rc::new(RefCell::new(
|
||||
|
|
Loading…
Reference in a new issue