Open zakstucke opened 1 month ago
The example I gave in the other issue (#3038) does work, though, which is odd. Maybe worth investigating what the difference is between those two cases?
#[component]
pub fn App() -> impl IntoView {
view! {
<Router>
<Routes fallback=|| {
view! { <p>404</p> }
}>
<ParentRoute path=path!("/") view=AuthCheck>
<Route path=path!("/") view=Home/>
<Route path=path!("/other") view=Other/>
</ParentRoute>
</Routes>
</Router>
}
}
#[component]
fn AuthCheck() -> impl IntoView {
let resource = Resource::new_blocking(
|| (),
move |_| async move {
#[cfg(feature = "hydrate")]
send_wrapper::SendWrapper::new(
gloo_timers::future::TimeoutFuture::new(1000),
)
.await;
#[cfg(feature = "ssr")]
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
Some("user_info...".to_string())
},
);
let inner_view = Suspend::new(async move {
let user_info = resource.await;
provide_context(user_info.clone());
(
if user_info.is_some() {
Either::Left(view! {
<div>
<p>"Logged in!"</p>
</div>
})
} else {
Either::Right(view! { <p>"Logged out!"</p> })
},
Outlet(),
)
});
view! { <Suspense>{inner_view}</Suspense> }
}
#[component]
fn Home() -> impl IntoView {
let user_info = expect_context::<Option<String>>();
format!("{user_info:?}")
}
#[component]
fn Other() -> impl IntoView {
"Other Page"
}
Hey @gbj , the difference is I have move || Suspend(...)
in this repro, in yours you forgot to make Suspend
reactive (it's reactive in any other 0.7 example i've seen), which works in the limited repro you gave, but breaks in a bunch of other ways.
If nonreactive Suspend
is actually meant to work, I can open a separate issue as to how it doesn't work.
But yeah if you change Suspend
-> move || Suspend
in your repro from the last issue, you hit this error too.
Ah okay, I see.
So, here's the problem:
Currently, an Outlet
's view is slotted into the ownership tree as the child of the parent route's view, not as the child of the location where it's used. So the move ||
and the Outlet
are actually siblings in the ownership graph. (This may be confusing; I'm happy to expand on it if it's helpful.)
A workaround is pretty straightforward, and consists of providing the context in the parent Owner:
let outer_owner = Owner::current().unwrap();
let inner_view = move || {
Suspend::new({
let outer_owner = outer_owner.clone();
async move {
let auth_state = r_auth_state.await;
provide_context(CtxInsideSuspense);
Outlet()
}
})
};
view! { <Suspense>{inner_view}</Suspense> }
I think it is possible to fix this, but setting the ownership/context relationships between nested routes is relatively tricky so it will take a bit more time than I have at the moment.
Got it, the workaround seems to work for now thank you.
It might be worth editing your workaround snippet with outer_owner.with(|| provide_context(...))
which I think you missed, to help anyone else reading this before it's fixed.
so it will take a bit more time than I have at the moment
Totally understand, thanks for putting up with my tsunami of issues the last few days! At the very least I hope I helped push towards a stable 0.7.
Describe the bug Trying to implement recommended approach we were discussing, providing context inside suspend doesn't seem to work.
Tested in the
counter_isomorphic
example.Leptos Dependencies Git
To Reproduce