mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 10:11:56 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55ea00afdd | ||
|
|
f7d5567a35 |
@@ -259,20 +259,22 @@ where
|
||||
let options = options.clone();
|
||||
let app_fn = app_fn.clone();
|
||||
let res_options = ResponseOptions::default();
|
||||
let status = RouterStatusContext::default();
|
||||
|
||||
async move {
|
||||
let app = {
|
||||
let app_fn = app_fn.clone();
|
||||
let res_options = res_options.clone();
|
||||
let status = status.clone();
|
||||
move |cx| {
|
||||
provide_contexts(cx, &req, res_options);
|
||||
provide_contexts(cx, &req, res_options, status);
|
||||
(app_fn)(cx).into_view(cx)
|
||||
}
|
||||
};
|
||||
|
||||
let (head, tail) = html_parts(&options);
|
||||
|
||||
stream_app(app, head, tail, res_options).await
|
||||
stream_app(app, head, tail, res_options, status).await
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -336,6 +338,7 @@ where
|
||||
let app_fn = app_fn.clone();
|
||||
let data_fn = data_fn.clone();
|
||||
let res_options = ResponseOptions::default();
|
||||
let status = RouterStatusContext::default();
|
||||
|
||||
async move {
|
||||
let data = match data_fn(req.clone()).await {
|
||||
@@ -347,24 +350,31 @@ where
|
||||
let app = {
|
||||
let app_fn = app_fn.clone();
|
||||
let res_options = res_options.clone();
|
||||
let status = status.clone();
|
||||
move |cx| {
|
||||
provide_contexts(cx, &req, res_options);
|
||||
provide_contexts(cx, &req, res_options, status);
|
||||
(app_fn)(cx, data).into_view(cx)
|
||||
}
|
||||
};
|
||||
|
||||
let (head, tail) = html_parts(&options);
|
||||
|
||||
stream_app(app, head, tail, res_options).await
|
||||
stream_app(app, head, tail, res_options, status).await
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn provide_contexts(cx: leptos::Scope, req: &HttpRequest, res_options: ResponseOptions) {
|
||||
fn provide_contexts(
|
||||
cx: leptos::Scope,
|
||||
req: &HttpRequest,
|
||||
res_options: ResponseOptions,
|
||||
status: RouterStatusContext,
|
||||
) {
|
||||
let path = leptos_corrected_path(req);
|
||||
|
||||
let integration = ServerIntegration { path };
|
||||
provide_context(cx, RouterIntegrationContext::new(integration));
|
||||
provide_context(cx, status);
|
||||
provide_context(cx, MetaContext::new());
|
||||
provide_context(cx, res_options);
|
||||
provide_context(cx, req.clone());
|
||||
@@ -385,6 +395,7 @@ async fn stream_app(
|
||||
head: String,
|
||||
tail: String,
|
||||
res_options: ResponseOptions,
|
||||
router_status: RouterStatusContext,
|
||||
) -> HttpResponse<BoxBody> {
|
||||
let (stream, runtime, _) = render_to_stream_with_prefix_undisposed(app, move |cx| {
|
||||
let head = use_context::<MetaContext>(cx)
|
||||
@@ -411,7 +422,15 @@ async fn stream_app(
|
||||
let res_options = res_options.0.read().await;
|
||||
|
||||
let (status, mut headers) = (res_options.status, res_options.headers.clone());
|
||||
let status = status.unwrap_or_default();
|
||||
let status = status.unwrap_or_else(|| {
|
||||
router_status
|
||||
.status
|
||||
.read()
|
||||
.ok()
|
||||
.and_then(|s| s.map(|s| StatusCode::from_u16(s).ok()))
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
});
|
||||
|
||||
let complete_stream = futures::stream::iter([
|
||||
first_chunk.unwrap(),
|
||||
|
||||
@@ -318,6 +318,8 @@ where
|
||||
let default_res_options = ResponseOptions::default();
|
||||
let res_options2 = default_res_options.clone();
|
||||
let res_options3 = default_res_options.clone();
|
||||
let router_status = RouterStatusContext::default();
|
||||
let router_status2 = router_status.clone();
|
||||
|
||||
async move {
|
||||
// Need to get the path and query string of the Request
|
||||
@@ -403,6 +405,7 @@ where
|
||||
cx,
|
||||
RouterIntegrationContext::new(integration),
|
||||
);
|
||||
provide_context(cx, router_status2);
|
||||
provide_context(cx, MetaContext::new());
|
||||
provide_context(cx, req_parts);
|
||||
provide_context(cx, default_res_options);
|
||||
@@ -471,9 +474,16 @@ where
|
||||
Box::pin(complete_stream) as PinnedHtmlStream
|
||||
));
|
||||
|
||||
if let Some(status) = res_options.status {
|
||||
*res.status_mut() = status
|
||||
}
|
||||
let status = res_options.status.unwrap_or_else(|| {
|
||||
router_status
|
||||
.status
|
||||
.read()
|
||||
.ok()
|
||||
.and_then(|s| s.map(|s| StatusCode::from_u16(s).ok()))
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
});
|
||||
*res.status_mut() = status;
|
||||
let mut res_headers = res_options.headers.clone();
|
||||
res.headers_mut().extend(res_headers.drain());
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ fn simple_ssr_test() {
|
||||
|
||||
assert_eq!(
|
||||
rendered.into_view(cx).render_to_string(cx),
|
||||
"<div id=\"_0-1\"><button id=\"_0-2\">-1</button><span id=\"_0-3\">Value: <!--hk=_0-4o|leptos-dyn-child-start-->0<!--hk=_0-4c|leptos-dyn-child-end-->!</span><button id=\"_0-5\">+1</button></div>"
|
||||
"<div id=\"_0-1\"><button id=\"_0-2\">-1</button><span id=\"_0-3\">Value: <leptos-dyn-child-start leptos id=\"_0-4o\"></leptos-dyn-child-start>0<leptos-dyn-child-end leptos id=\"_0-4c\"></leptos-dyn-child-end>!</span><button id=\"_0-5\">+1</button></div>"
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -50,7 +50,7 @@ fn ssr_test_with_components() {
|
||||
|
||||
assert_eq!(
|
||||
rendered.into_view(cx).render_to_string(cx),
|
||||
"<div class=\"counters\" id=\"_0-1\"><!--hk=_0-1-0o|leptos-counter-start--><div id=\"_0-1-1\"><button id=\"_0-1-2\">-1</button><span id=\"_0-1-3\">Value: <!--hk=_0-1-4o|leptos-dyn-child-start-->1<!--hk=_0-1-4c|leptos-dyn-child-end-->!</span><button id=\"_0-1-5\">+1</button></div><!--hk=_0-1-0c|leptos-counter-end--><!--hk=_0-1-5-0o|leptos-counter-start--><div id=\"_0-1-5-1\"><button id=\"_0-1-5-2\">-1</button><span id=\"_0-1-5-3\">Value: <!--hk=_0-1-5-4o|leptos-dyn-child-start-->2<!--hk=_0-1-5-4c|leptos-dyn-child-end-->!</span><button id=\"_0-1-5-5\">+1</button></div><!--hk=_0-1-5-0c|leptos-counter-end--></div>"
|
||||
"<div class=\"counters\" id=\"_0-1\"><leptos-counter-start leptos id=\"_0-1-0o\"></leptos-counter-start><div id=\"_0-1-1\"><button id=\"_0-1-2\">-1</button><span id=\"_0-1-3\">Value: <leptos-dyn-child-start leptos id=\"_0-1-4o\"></leptos-dyn-child-start>1<leptos-dyn-child-end leptos id=\"_0-1-4c\"></leptos-dyn-child-end>!</span><button id=\"_0-1-5\">+1</button></div><leptos-counter-end leptos id=\"_0-1-0c\"></leptos-counter-end><leptos-counter-start leptos id=\"_0-1-5-0o\"></leptos-counter-start><div id=\"_0-1-5-1\"><button id=\"_0-1-5-2\">-1</button><span id=\"_0-1-5-3\">Value: <leptos-dyn-child-start leptos id=\"_0-1-5-4o\"></leptos-dyn-child-start>2<leptos-dyn-child-end leptos id=\"_0-1-5-4c\"></leptos-dyn-child-end>!</span><button id=\"_0-1-5-5\">+1</button></div><leptos-counter-end leptos id=\"_0-1-5-0c\"></leptos-counter-end></div>"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ features = [
|
||||
"Range",
|
||||
"Text",
|
||||
"HtmlCollection",
|
||||
"TreeWalker",
|
||||
|
||||
# Events we cast to in leptos_macro -- added here so we don't force users to import them
|
||||
"AnimationEvent",
|
||||
|
||||
@@ -1,51 +1,21 @@
|
||||
use cfg_if::cfg_if;
|
||||
use std::{cell::RefCell, fmt::Display};
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
use once_cell::unsync::Lazy as LazyCell;
|
||||
use std::collections::HashMap;
|
||||
use wasm_bindgen::JsCast;
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use once_cell::unsync::Lazy as LazyCell;
|
||||
|
||||
// We can tell if we start in hydration mode by checking to see if the
|
||||
// id "_0-0-0" is present in the DOM. If it is, we know we are hydrating from
|
||||
// the server, if not, we are starting off in CSR
|
||||
thread_local! {
|
||||
static HYDRATION_COMMENTS: LazyCell<HashMap<String, web_sys::Comment>> = LazyCell::new(|| {
|
||||
let document = crate::document();
|
||||
let body = document.body().unwrap();
|
||||
let walker = document
|
||||
.create_tree_walker_with_what_to_show(&body, 128)
|
||||
.unwrap();
|
||||
let mut map = HashMap::new();
|
||||
while let Ok(Some(node)) = walker.next_node() {
|
||||
if let Some(content) = node.text_content() {
|
||||
if let Some(hk) = content.strip_prefix("hk=") {
|
||||
if let Some(hk) = hk.split("|").next() {
|
||||
map.insert(hk.into(), node.unchecked_into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
map
|
||||
});
|
||||
// We can tell if we start in hydration mode by checking to see if the
|
||||
// id "_0-0-0" is present in the DOM. If it is, we know we are hydrating from
|
||||
// the server, if not, we are starting off in CSR
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
thread_local! {
|
||||
static IS_HYDRATING: RefCell<LazyCell<bool>> = RefCell::new(LazyCell::new(|| {
|
||||
#[cfg(debug_assertions)]
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some()
|
||||
|| crate::document().get_element_by_id("_0-0-0o").is_some();
|
||||
|
||||
static IS_HYDRATING: RefCell<LazyCell<bool>> = RefCell::new(LazyCell::new(|| {
|
||||
#[cfg(debug_assertions)]
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some()
|
||||
|| crate::document().get_element_by_id("_0-0-0o").is_some()
|
||||
|| HYDRATION_COMMENTS.with(|comments| comments.get("_0-0-0o").is_some());
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some()
|
||||
|| HYDRATION_COMMENTS.with(|comments| comments.get("_0-0-0").is_some());
|
||||
}));
|
||||
}
|
||||
|
||||
pub(crate) fn get_marker(id: &str) -> Option<web_sys::Comment> {
|
||||
HYDRATION_COMMENTS.with(|comments| comments.get(id).cloned())
|
||||
}
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some();
|
||||
}));
|
||||
}
|
||||
|
||||
/// A stable identifer within the server-rendering or hydration process.
|
||||
|
||||
@@ -303,7 +303,7 @@ impl Comment {
|
||||
if HydrationCtx::is_hydrating() {
|
||||
let id = HydrationCtx::to_string(id, closing);
|
||||
|
||||
if let Some(marker) = hydration::get_marker(&id) {
|
||||
if let Some(marker) = document().get_element_by_id(&id) {
|
||||
marker.before_with_node_1(&node).unwrap();
|
||||
|
||||
marker.remove();
|
||||
@@ -548,7 +548,7 @@ impl View {
|
||||
pub fn on<E: ev::EventDescriptor + 'static>(
|
||||
self,
|
||||
event: E,
|
||||
#[allow(unused_mut)] mut event_handler: impl FnMut(E::EventType) + 'static,
|
||||
mut event_handler: impl FnMut(E::EventType) + 'static,
|
||||
) -> Self {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::borrow::Cow;
|
||||
/// <p>"Hello, world!"</p>
|
||||
/// });
|
||||
/// // static HTML includes some hydration info
|
||||
/// assert_eq!(html, "<p id=\"_0-1\">Hello, world!</p>");
|
||||
/// assert_eq!(html, "<style>[leptos]{display:none;}</style><p id=\"_0-1\">Hello, world!</p>");
|
||||
/// # }}
|
||||
/// ```
|
||||
pub fn render_to_string<F, N>(f: F) -> String
|
||||
@@ -33,7 +33,13 @@ where
|
||||
|
||||
runtime.dispose();
|
||||
|
||||
html.into()
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
format!("<style>[leptos]{{display:none;}}</style>{html}")
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
format!("<style>l-m{{display:none;}}</style>{html}")
|
||||
}
|
||||
|
||||
/// Renders a function to a stream of HTML strings.
|
||||
@@ -116,6 +122,16 @@ pub fn render_to_stream_with_prefix_undisposed(
|
||||
let pending_resources = serde_json::to_string(&resources).unwrap();
|
||||
let prefix = prefix(cx);
|
||||
|
||||
let shell = {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
format!("<style>[leptos]{{display:none;}}</style>{shell}")
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
format!("<style>l-m{{display:none;}}</style>{shell}")
|
||||
};
|
||||
|
||||
(
|
||||
shell,
|
||||
prefix,
|
||||
@@ -202,7 +218,7 @@ impl View {
|
||||
};
|
||||
cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
format!(r#"<!--hk={}|leptos-{name}-start-->{}<!--hk={}|leptos-{name}-end-->"#,
|
||||
format!(r#"<leptos-{name}-start leptos id="{}"></leptos-{name}-start>{}<leptos-{name}-end leptos id="{}"></leptos-{name}-end>"#,
|
||||
HydrationCtx::to_string(&node.id, false),
|
||||
content(),
|
||||
HydrationCtx::to_string(&node.id, true),
|
||||
@@ -210,7 +226,7 @@ impl View {
|
||||
).into()
|
||||
} else {
|
||||
format!(
|
||||
r#"{}<!--hk={}-->"#,
|
||||
r#"{}<l-m id="{}"></l-m>"#,
|
||||
content(),
|
||||
HydrationCtx::to_string(&node.id, true)
|
||||
).into()
|
||||
@@ -227,14 +243,14 @@ impl View {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
format!(
|
||||
"<!--hk={}|leptos-unit-->",
|
||||
"<leptos-unit leptos id={}></leptos-unit>",
|
||||
HydrationCtx::to_string(&u.id, true)
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
format!("<!--hk={}-->", HydrationCtx::to_string(&u.id, true))
|
||||
format!("<l-m id={}></l-m>", HydrationCtx::to_string(&u.id, true))
|
||||
.into()
|
||||
}) as Box<dyn FnOnce() -> Cow<'static, str>>,
|
||||
),
|
||||
@@ -270,6 +286,7 @@ impl View {
|
||||
}
|
||||
CoreComponent::Each(node) => {
|
||||
let children = node.children.take();
|
||||
|
||||
(
|
||||
node.id,
|
||||
"each",
|
||||
@@ -286,8 +303,10 @@ impl View {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
format!(
|
||||
"<!--hk={}|leptos-each-item-start-->{}<!\
|
||||
--hk={}|leptos-each-item-end-->",
|
||||
"<leptos-each-item-start leptos \
|
||||
id=\"{}\"></\
|
||||
leptos-each-item-start>{}<leptos-each-item-end \
|
||||
leptos id=\"{}\"></leptos-each-item-end>",
|
||||
HydrationCtx::to_string(&id, false),
|
||||
content(),
|
||||
HydrationCtx::to_string(&id, true),
|
||||
@@ -296,7 +315,7 @@ impl View {
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
format!(
|
||||
"{}<!--hk={}-->",
|
||||
"{}<l-m id=\"{}\"></l-m>",
|
||||
content(),
|
||||
HydrationCtx::to_string(&id, true)
|
||||
)
|
||||
@@ -312,7 +331,7 @@ impl View {
|
||||
cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
format!(
|
||||
r#"<!--hk={}|leptos-{name}-start-->{}<!--hk={}|leptos-{name}-end-->"#,
|
||||
r#"<leptos-{name}-start leptos id="{}"></leptos-{name}-start>{}<leptos-{name}-end leptos id="{}"></leptos-{name}-end>"#,
|
||||
HydrationCtx::to_string(&id, false),
|
||||
content(),
|
||||
HydrationCtx::to_string(&id, true),
|
||||
@@ -321,7 +340,7 @@ impl View {
|
||||
let _ = name;
|
||||
|
||||
format!(
|
||||
r#"{}<!--hk={}-->"#,
|
||||
r#"{}<l-m id="{}"></l-m>"#,
|
||||
content(),
|
||||
HydrationCtx::to_string(&id, true)
|
||||
).into()
|
||||
|
||||
@@ -208,10 +208,10 @@ impl MetaContext {
|
||||
/// // `app` contains only the body content w/ hydration stuff, not the meta tags
|
||||
/// assert_eq!(
|
||||
/// app.into_view(cx).render_to_string(cx),
|
||||
/// "<main id=\"_0-1\"><!--hk=_0-2c|leptos-unit--><!--hk=_0-4c|leptos-unit--><p id=\"_0-5\">Some text</p></main>"
|
||||
/// "<main id=\"_0-1\"><leptos-unit leptos id=_0-2c></leptos-unit><leptos-unit leptos id=_0-4c></leptos-unit><p id=\"_0-5\">Some text</p></main>"
|
||||
/// );
|
||||
/// // `MetaContext::dehydrate()` gives you HTML that should be in the `<head>`
|
||||
/// assert_eq!(use_head(cx).dehydrate(), "<title>my title</title><link id=\"leptos-link-1\" href=\"/style.css\" rel=\"stylesheet\" leptos-hk=\"_0-3\"/>")
|
||||
/// assert_eq!(use_head(cx).dehydrate(), r#"<title>my title</title><link id="leptos-link-1" href="/style.css" rel="stylesheet" leptos-hk="_0-3"/>"#)
|
||||
/// });
|
||||
/// # }
|
||||
/// ```
|
||||
|
||||
@@ -138,7 +138,7 @@ impl RouteContext {
|
||||
self.inner.params
|
||||
}
|
||||
|
||||
pub(crate) fn base(cx: Scope, path: &str, fallback: Option<fn() -> View>) -> Self {
|
||||
pub(crate) fn base(cx: Scope, path: &str, fallback: Option<fn(Scope) -> View>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(RouteContextInner {
|
||||
cx,
|
||||
@@ -148,7 +148,7 @@ impl RouteContext {
|
||||
path: path.to_string(),
|
||||
original_path: path.to_string(),
|
||||
params: create_memo(cx, |_| ParamsMap::new()),
|
||||
outlet: Box::new(move || fallback.map(|f| f().into_view(cx))),
|
||||
outlet: Box::new(move || fallback.as_ref().map(move |f| f(cx))),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use cfg_if::cfg_if;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use leptos::*;
|
||||
use thiserror::Error;
|
||||
@@ -28,7 +32,7 @@ pub fn Router(
|
||||
base: Option<&'static str>,
|
||||
/// A fallback that should be shown if no route is matched.
|
||||
#[prop(optional)]
|
||||
fallback: Option<fn() -> View>,
|
||||
fallback: Option<fn(Scope) -> View>,
|
||||
/// The `<Router/>` should usually wrap your whole page. It can contain
|
||||
/// any elements, and should include a [Routes](crate::Routes) component somewhere
|
||||
/// to define and display [Route](crate::Route)s.
|
||||
@@ -61,6 +65,14 @@ pub(crate) struct RouterContextInner {
|
||||
set_state: WriteSignal<State>,
|
||||
}
|
||||
|
||||
/// Context type that indicates the status of the last request
|
||||
/// (i.e., whether it was not found, or had an error.)
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RouterStatusContext {
|
||||
pub status: Arc<RwLock<Option<u16>>>,
|
||||
pub message: Arc<RwLock<Option<String>>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RouterContextInner {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RouterContextInner")
|
||||
@@ -80,7 +92,7 @@ impl RouterContext {
|
||||
pub(crate) fn new(
|
||||
cx: Scope,
|
||||
base: Option<&'static str>,
|
||||
fallback: Option<fn() -> View>,
|
||||
fallback: Option<fn(Scope) -> View>,
|
||||
) -> Self {
|
||||
cfg_if! {
|
||||
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
expand_optionals, get_route_matches, join_paths, Branch, Matcher, RouteDefinition,
|
||||
RouteMatch,
|
||||
},
|
||||
RouteContext, RouterContext,
|
||||
RouteContext, RouterContext, RouterStatusContext,
|
||||
};
|
||||
|
||||
/// Contains route definitions and manages the actual routing process.
|
||||
@@ -28,6 +28,7 @@ pub fn Routes(
|
||||
log::warn!("<Routes/> component should be nested within a <Router/>.");
|
||||
panic!()
|
||||
});
|
||||
let base_route = router.base();
|
||||
|
||||
let mut branches = Vec::new();
|
||||
let id_before = HydrationCtx::peek();
|
||||
@@ -189,19 +190,35 @@ pub fn Routes(
|
||||
});
|
||||
|
||||
// show the root route
|
||||
let router_status = use_context::<RouterStatusContext>(cx);
|
||||
let root = create_memo(cx, move |prev| {
|
||||
provide_context(cx, route_states);
|
||||
let router_status = router_status.clone();
|
||||
route_states.with(|state| {
|
||||
let root = state.routes.borrow();
|
||||
let root = root.get(0);
|
||||
if let Some(route) = root {
|
||||
provide_context(cx, route.clone());
|
||||
}
|
||||
|
||||
if prev.is_none() || !root_equal.get() {
|
||||
root.as_ref().map(|route| route.outlet().into_view(cx))
|
||||
if state.routes.borrow().is_empty() {
|
||||
if let Some(status) = router_status {
|
||||
if let Ok(mut lock) = status.status.write() {
|
||||
*lock = Some(404);
|
||||
}
|
||||
}
|
||||
Some(base_route.outlet().into_view(cx))
|
||||
} else {
|
||||
prev.cloned().unwrap()
|
||||
if let Some(status) = router_status {
|
||||
if let Ok(mut lock) = status.status.write() {
|
||||
*lock = None;
|
||||
}
|
||||
}
|
||||
let root = state.routes.borrow();
|
||||
let root = root.get(0);
|
||||
if let Some(route) = root {
|
||||
provide_context(cx, route.clone());
|
||||
}
|
||||
|
||||
if prev.is_none() || !root_equal.get() {
|
||||
root.as_ref().map(|route| route.outlet().into_view(cx))
|
||||
} else {
|
||||
prev.cloned().unwrap()
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user