Make router integration easier

This commit is contained in:
Greg Johnston 2022-09-30 15:57:35 -04:00
parent 0e60228f9b
commit 862258e035
2 changed files with 29 additions and 10 deletions

View file

@ -7,7 +7,7 @@ use leptos_dom::{Element, IntoChild, UnwrapThrowExt};
use leptos_macro::view;
use leptos_reactive::{
create_memo, create_render_effect, create_signal, provide_context, Memo,
ReadSignal, Scope, ScopeDisposer, WriteSignal,
ReadSignal, Scope, ScopeDisposer, WriteSignal, use_context,
};
use thiserror::Error;
use typed_builder::TypedBuilder;
@ -19,17 +19,15 @@ use wasm_bindgen::JsCast;
use leptos_reactive::use_transition;
use crate::{
RouterIntegrationContext,
create_location,
matching::{get_route_matches, resolve_path, Branch, RouteMatch},
unescape, History, Location, LocationChange, RouteContext, State, Url,
};
#[derive(TypedBuilder)]
pub struct RouterProps<H>
where
H: History + 'static
pub struct RouterProps
{
mode: H,
#[builder(default, setter(strip_option))]
base: Option<&'static str>,
#[builder(default, setter(strip_option))]
@ -38,12 +36,10 @@ where
}
#[allow(non_snake_case)]
pub fn Router<H>(cx: Scope, props: RouterProps<H>) -> impl IntoChild
where
H: History + 'static
pub fn Router(cx: Scope, props: RouterProps) -> impl IntoChild
{
// create a new RouterContext and provide it to every component beneath the router
let router = RouterContext::new(cx, props.mode, props.base, props.fallback);
let router = RouterContext::new(cx, props.base, props.fallback);
provide_context(cx, router.clone());
// whenever path changes, update matches
@ -204,10 +200,14 @@ impl std::fmt::Debug for RouterContextInner {
impl RouterContext {
pub fn new(
cx: Scope,
history: impl History + 'static,
base: Option<&'static str>,
fallback: Option<fn() -> Element>,
) -> Self {
#[cfg(any(feature = "csr", feature = "hydrate"))]
let history = use_context::<RouterIntegrationContext>(cx).unwrap_or_else(|| RouterIntegrationContext(Rc::new(crate::BrowserIntegration { })));
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
let history = use_context::<RouterIntegrationContext>(cx).expect("You must call provide_context::<RouterIntegrationContext>(cx, ...) somewhere above the <Router/>.");
// Any `History` type gives a way to get a reactive signal of the current location
// in the browser context, this is drawn from the `popstate` event
// different server adapters can provide different `History` implementations to allow server routing

View file

@ -15,6 +15,12 @@ pub use location::*;
pub use params::*;
pub use state::*;
impl std::fmt::Debug for RouterIntegrationContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RouterIntegrationContext").finish()
}
}
pub trait History {
fn location(&self, cx: Scope) -> ReadSignal<LocationChange>;
@ -109,3 +115,16 @@ impl History for BrowserIntegration {
log::debug!("[BrowserIntegration::navigate 5]");
}
}
#[derive(Clone)]
pub struct RouterIntegrationContext(pub std::rc::Rc<dyn History>);
impl History for RouterIntegrationContext {
fn location(&self, cx: Scope) -> ReadSignal<LocationChange> {
self.0.location(cx)
}
fn navigate(&self, loc: &LocationChange) {
self.0.navigate(loc)
}
}