mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 14:54:16 +00:00
fix ErrorBoundary/Suspense
This commit is contained in:
parent
c06110128b
commit
cc2714c03d
8 changed files with 62 additions and 33 deletions
|
@ -25,7 +25,7 @@ type CatCount = usize;
|
|||
|
||||
async fn fetch_cats(count: CatCount) -> Result<Vec<String>> {
|
||||
if count > 0 {
|
||||
gloo_timers::future::TimeoutFuture::new(1000).await;
|
||||
gloo_timers::future::TimeoutFuture::new(250).await;
|
||||
// make the request
|
||||
let res = reqwasm::http::Request::get(&format!(
|
||||
"https://api.thecatapi.com/v1/images/search?limit={count}",
|
||||
|
@ -103,7 +103,7 @@ pub fn fetch_example() -> impl IntoView {
|
|||
/>
|
||||
</label>
|
||||
<ErrorBoundary fallback>
|
||||
<Suspense fallback=|| view! { <div>"Loading..."</div> }>
|
||||
<Transition fallback=|| view! { <div>"Loading..."</div> }>
|
||||
<ul>
|
||||
{
|
||||
async move {
|
||||
|
@ -116,7 +116,7 @@ pub fn fetch_example() -> impl IntoView {
|
|||
.suspend()
|
||||
}
|
||||
</ul>
|
||||
</Suspense>
|
||||
</Transition>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ use reactive_graph::{
|
|||
computed::ArcMemo,
|
||||
effect::RenderEffect,
|
||||
signal::ArcRwSignal,
|
||||
traits::{Get, GetUntracked, Track, Update, With},
|
||||
traits::{GetUntracked, Track, Update, With},
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use tachys::{
|
||||
either::Either,
|
||||
reactive_graph::RenderEffectState,
|
||||
renderer::Renderer,
|
||||
view::{Mountable, Render, RenderHtml},
|
||||
};
|
||||
|
@ -232,7 +231,7 @@ where
|
|||
Either::Left(chil) => chil.unmount(),
|
||||
Either::Right((fal, _)) => fal.unmount(),
|
||||
});
|
||||
//self.placeholder.unmount();
|
||||
self.placeholder.unmount();
|
||||
}
|
||||
|
||||
fn mount(
|
||||
|
|
|
@ -47,13 +47,10 @@ where
|
|||
let fallback = move || fallback.clone().run();
|
||||
// TODO check this against islands
|
||||
move || {
|
||||
crate::logging::log!("running innner thing");
|
||||
untrack(|| {
|
||||
SuspenseBoundary::<false, _, _>::new(
|
||||
fallback.clone(),
|
||||
(children.clone())(),
|
||||
)
|
||||
})
|
||||
SuspenseBoundary::<false, _, _>::new(
|
||||
fallback.clone(),
|
||||
(children.clone())(),
|
||||
)
|
||||
// TODO track
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
use crate::{children::ViewFn, AsyncChildren, IntoView};
|
||||
use crate::{
|
||||
children::{TypedChildrenFn, ViewFn},
|
||||
IntoView,
|
||||
};
|
||||
use leptos_macro::component;
|
||||
use std::{future::Future, sync::Arc};
|
||||
use tachys::prelude::FutureViewExt;
|
||||
use tachys::async_views::SuspenseBoundary;
|
||||
|
||||
/// TODO docs!
|
||||
#[component]
|
||||
pub fn Transition<Chil, ChilFn, ChilFut>(
|
||||
pub fn Transition<Chil>(
|
||||
#[prop(optional, into)] fallback: ViewFn,
|
||||
children: AsyncChildren<Chil, ChilFn, ChilFut>,
|
||||
children: TypedChildrenFn<Chil>,
|
||||
) -> impl IntoView
|
||||
where
|
||||
Chil: IntoView + 'static,
|
||||
ChilFn: Fn() -> ChilFut + Clone + Send + 'static,
|
||||
ChilFut: Future<Output = Chil> + Send + 'static,
|
||||
{
|
||||
let children = children.into_inner();
|
||||
let fallback = move || fallback.clone().run();
|
||||
// TODO check this against islands
|
||||
move || {
|
||||
children()
|
||||
.suspend()
|
||||
.transition()
|
||||
.with_fallback(fallback.run())
|
||||
.track()
|
||||
SuspenseBoundary::<true, _, _>::new(
|
||||
fallback.clone(),
|
||||
(children.clone())(),
|
||||
)
|
||||
// TODO track
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ where
|
|||
async move {
|
||||
let value = fut.await;
|
||||
let mut state = state.borrow_mut();
|
||||
let fut = Either::<Fal, Chil::AsyncOutput>::Right(value)
|
||||
|
||||
Either::<Fal, Chil::AsyncOutput>::Right(value)
|
||||
.rebuild(&mut *state);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -77,12 +77,30 @@ pub trait Renderer: Sized + Debug {
|
|||
M: Mountable<Self>,
|
||||
{
|
||||
let parent = Self::Element::cast_from(
|
||||
Self::get_parent(before).expect("node should have parent"),
|
||||
Self::get_parent(before).expect("could not find parent element"),
|
||||
)
|
||||
.expect("placeholder parent should be Element");
|
||||
new_child.mount(&parent, Some(before));
|
||||
}
|
||||
|
||||
/// Tries to mount the new child before the marker as its sibling.
|
||||
///
|
||||
/// Returns `false` if the child did not have a valid parent.
|
||||
#[track_caller]
|
||||
fn try_mount_before<M>(new_child: &mut M, before: &Self::Node) -> bool
|
||||
where
|
||||
M: Mountable<Self>,
|
||||
{
|
||||
if let Some(parent) =
|
||||
Self::get_parent(before).and_then(Self::Element::cast_from)
|
||||
{
|
||||
new_child.mount(&parent, Some(before));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the child node from the parents, and returns the removed node.
|
||||
fn remove_node(
|
||||
parent: &Self::Element,
|
||||
|
|
|
@ -52,13 +52,13 @@ where
|
|||
(Either::Right(new), Either::Left(old)) => {
|
||||
old.unmount();
|
||||
let mut new_state = new.build();
|
||||
Rndr::mount_before(&mut new_state, marker);
|
||||
Rndr::try_mount_before(&mut new_state, marker);
|
||||
state.state = Either::Right(new_state);
|
||||
}
|
||||
(Either::Left(new), Either::Right(old)) => {
|
||||
old.unmount();
|
||||
let mut new_state = new.build();
|
||||
Rndr::mount_before(&mut new_state, marker);
|
||||
Rndr::try_mount_before(&mut new_state, marker);
|
||||
state.state = Either::Left(new_state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ where
|
|||
(Err(err), Ok(new)) => {
|
||||
any_error::clear(err);
|
||||
let mut new_state = new.build();
|
||||
R::mount_before(&mut new_state, state.placeholder.as_ref());
|
||||
R::try_mount_before(&mut new_state, state.placeholder.as_ref());
|
||||
state.state = Ok(new_state);
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,20 @@ where
|
|||
state: Result<T, any_error::ErrorId>,
|
||||
}
|
||||
|
||||
impl<T, R> Drop for ResultState<T, R>
|
||||
where
|
||||
T: Mountable<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
// when the state is cleared, unregister this error; this item is being dropped and its
|
||||
// error should no longer be shown
|
||||
if let Err(e) = &self.state {
|
||||
any_error::clear(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> Mountable<R> for ResultState<T, R>
|
||||
where
|
||||
T: Mountable<R>,
|
||||
|
@ -92,9 +106,7 @@ where
|
|||
if let Ok(ref mut state) = self.state {
|
||||
state.unmount();
|
||||
}
|
||||
// TODO investigate: including this seems to break error boundaries, although it doesn't
|
||||
// make sense to me why it would be a problem
|
||||
// self.placeholder.unmount();
|
||||
self.placeholder.unmount();
|
||||
}
|
||||
|
||||
fn mount(&mut self, parent: &R::Element, marker: Option<&R::Node>) {
|
||||
|
|
Loading…
Reference in a new issue