mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Fix issues with route matching on different sub-routes with same path (closes issue #229)
This commit is contained in:
parent
ca679ec496
commit
e2a5c2d78f
4 changed files with 31 additions and 11 deletions
|
@ -1,4 +1,4 @@
|
|||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
use crate::use_route;
|
||||
use leptos::*;
|
||||
|
@ -8,21 +8,18 @@ use leptos::*;
|
|||
#[component]
|
||||
pub fn Outlet(cx: Scope) -> impl IntoView {
|
||||
let route = use_route(cx);
|
||||
let is_showing = Rc::new(RefCell::new(None));
|
||||
let is_showing = Rc::new(Cell::new(None));
|
||||
let (outlet, set_outlet) = create_signal(cx, None);
|
||||
create_effect(cx, move |_| {
|
||||
let is_showing_val = { is_showing.borrow().clone() };
|
||||
match (route.child(), &is_showing_val) {
|
||||
match (route.child(), &is_showing.get()) {
|
||||
(None, _) => {
|
||||
set_outlet.set(None);
|
||||
}
|
||||
(Some(child), Some(_))
|
||||
if Some(child.original_path().to_string()) == is_showing_val =>
|
||||
{
|
||||
(Some(child), Some(is_showing_val)) if child.id() == *is_showing_val => {
|
||||
// do nothing: we don't need to rerender the component, because it's the same
|
||||
}
|
||||
(Some(child), _) => {
|
||||
*is_showing.borrow_mut() = Some(child.original_path().to_string());
|
||||
is_showing.set(Some(child.id()));
|
||||
provide_context(child.cx(), child.clone());
|
||||
set_outlet.set(Some(child.outlet().into_view(cx)))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, rc::Rc};
|
||||
use std::{borrow::Cow, cell::Cell, rc::Rc};
|
||||
|
||||
use leptos::*;
|
||||
|
||||
|
@ -7,6 +7,10 @@ use crate::{
|
|||
ParamsMap, RouterContext,
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
static ROUTE_ID: Cell<usize> = Cell::new(0);
|
||||
}
|
||||
|
||||
/// Describes a portion of the nested layout of the app, specifying the route it should match,
|
||||
/// the element it should display, and data that should be loaded alongside the route.
|
||||
#[component(transparent)]
|
||||
|
@ -43,7 +47,13 @@ where
|
|||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let id = ROUTE_ID.with(|id| {
|
||||
let next = id.get() + 1;
|
||||
id.set(next);
|
||||
next
|
||||
});
|
||||
RouteDefinition {
|
||||
id,
|
||||
path: path.to_string(),
|
||||
children,
|
||||
view: Rc::new(move |cx| view(cx).into_view(cx)),
|
||||
|
@ -73,7 +83,9 @@ impl RouteContext {
|
|||
let base = base.path();
|
||||
let RouteMatch { path_match, route } = matcher()?;
|
||||
let PathMatch { path, .. } = path_match;
|
||||
let RouteDefinition { view: element, .. } = route.key;
|
||||
let RouteDefinition {
|
||||
view: element, id, ..
|
||||
} = route.key;
|
||||
let params = create_memo(cx, move |_| {
|
||||
matcher()
|
||||
.map(|matched| matched.path_match.params)
|
||||
|
@ -83,6 +95,7 @@ impl RouteContext {
|
|||
Some(Self {
|
||||
inner: Rc::new(RouteContextInner {
|
||||
cx,
|
||||
id,
|
||||
base_path: base.to_string(),
|
||||
child: Box::new(child),
|
||||
path,
|
||||
|
@ -98,6 +111,10 @@ impl RouteContext {
|
|||
self.inner.cx
|
||||
}
|
||||
|
||||
pub(crate) fn id(&self) -> usize {
|
||||
self.inner.id
|
||||
}
|
||||
|
||||
/// Returns the URL path of the current route,
|
||||
/// including param values in their places.
|
||||
///
|
||||
|
@ -125,6 +142,7 @@ impl RouteContext {
|
|||
Self {
|
||||
inner: Rc::new(RouteContextInner {
|
||||
cx,
|
||||
id: 0,
|
||||
base_path: path.to_string(),
|
||||
child: Box::new(|| None),
|
||||
path: path.to_string(),
|
||||
|
@ -154,6 +172,7 @@ impl RouteContext {
|
|||
pub(crate) struct RouteContextInner {
|
||||
cx: Scope,
|
||||
base_path: String,
|
||||
pub(crate) id: usize,
|
||||
pub(crate) child: Box<dyn Fn() -> Option<RouteContext>>,
|
||||
pub(crate) path: String,
|
||||
pub(crate) original_path: String,
|
||||
|
|
|
@ -86,7 +86,8 @@ pub fn Routes(
|
|||
|
||||
match (prev_routes, prev_match) {
|
||||
(Some(prev), Some(prev_match))
|
||||
if next_match.route.key == prev_match.route.key =>
|
||||
if next_match.route.key == prev_match.route.key
|
||||
&& next_match.route.id == prev_match.route.id =>
|
||||
{
|
||||
let prev_one = { prev.borrow()[i].clone() };
|
||||
if i >= next.borrow().len() {
|
||||
|
@ -212,6 +213,7 @@ struct RouterState {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RouteData {
|
||||
pub id: usize,
|
||||
pub key: RouteDefinition,
|
||||
pub pattern: String,
|
||||
pub original_path: String,
|
||||
|
@ -286,6 +288,7 @@ fn create_routes(route_def: &RouteDefinition, base: &str) -> Vec<RouteData> {
|
|||
};
|
||||
acc.push(RouteData {
|
||||
key: route_def.clone(),
|
||||
id: route_def.id,
|
||||
matcher: Matcher::new_with_partial(&pattern, !is_leaf),
|
||||
pattern,
|
||||
original_path: original_path.to_string(),
|
||||
|
|
|
@ -5,6 +5,7 @@ use leptos::*;
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct RouteDefinition {
|
||||
pub id: usize,
|
||||
pub path: String,
|
||||
pub children: Vec<RouteDefinition>,
|
||||
pub view: Rc<dyn Fn(Scope) -> View>,
|
||||
|
|
Loading…
Reference in a new issue