mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Remove Memo
This commit is contained in:
parent
7cfebcbfee
commit
41f415160a
13 changed files with 42 additions and 388 deletions
|
@ -6,8 +6,6 @@ edition = "2021"
|
|||
[dependencies]
|
||||
leptos = { path = "../../leptos" }
|
||||
wee_alloc = "0.4"
|
||||
log = "0.4"
|
||||
console_log = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
|
|
|
@ -2,12 +2,11 @@ use leptos::*;
|
|||
|
||||
pub fn simple_counter(cx: Scope) -> web_sys::Element {
|
||||
let (value, set_value) = create_signal(cx, 0);
|
||||
log::debug!("ok");
|
||||
|
||||
view! {
|
||||
<div>
|
||||
<button on:click=move |_| set_value(|value| *value -= 1)>"-1"</button>
|
||||
<span>"Value: " {move || value().to_string()}</span>
|
||||
<span>{move || value().to_string()}</span>
|
||||
<button on:click=move |_| set_value(|value| *value += 1)>"+1"</button>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -5,6 +5,5 @@ use leptos::*;
|
|||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
pub fn main() {
|
||||
console_log::init_with_level(log::Level::Debug);
|
||||
mount_to_body(simple_counter)
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ impl<T> EffectState<T> {
|
|||
|
||||
fn cleanup(&self, id: (ScopeId, EffectId)) {
|
||||
for source in self.sources.borrow().iter() {
|
||||
source.unsubscribe(self.runtime, Subscriber::Effect(id))
|
||||
source.unsubscribe(self.runtime, Subscriber(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ where
|
|||
|
||||
// add it to the Scope stack, which means any signals called
|
||||
// in the effect fn immediately below will add this Effect as a dependency
|
||||
self.runtime.push_stack(Subscriber::Effect(id));
|
||||
self.runtime.push_stack(Subscriber(id));
|
||||
|
||||
// actually run the effect
|
||||
if let Some(transition) = self.runtime.running_transition() && self.render_effect {
|
||||
|
|
|
@ -1,299 +1,29 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Runtime, Scope, ScopeId, Source, Subscriber};
|
||||
use crate::{
|
||||
create_effect, create_signal, ReadSignal, Runtime, Scope, ScopeId, Source, Subscriber,
|
||||
};
|
||||
use std::{
|
||||
any::{type_name, Any},
|
||||
cell::RefCell,
|
||||
collections::HashSet,
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
pub fn create_memo<T>(cx: Scope, f: impl FnMut(Option<&T>) -> T + 'static) -> Memo<T>
|
||||
pub type Memo<T> = ReadSignal<T>;
|
||||
|
||||
pub fn create_memo<T>(cx: Scope, mut f: impl FnMut(Option<T>) -> T + 'static) -> Memo<T>
|
||||
where
|
||||
T: Debug + 'static,
|
||||
T: Clone + Debug + 'static,
|
||||
{
|
||||
let state = MemoState::new(cx.runtime, f);
|
||||
let initial = f(None);
|
||||
let (read, set) = create_signal(cx, initial);
|
||||
|
||||
let id = cx.push_memo(state);
|
||||
create_effect(cx, move |prev| {
|
||||
let new = f(prev);
|
||||
set(|n| *n = new.clone());
|
||||
new
|
||||
});
|
||||
|
||||
let eff = Memo {
|
||||
runtime: cx.runtime,
|
||||
scope: cx.id,
|
||||
id,
|
||||
ty: PhantomData,
|
||||
};
|
||||
|
||||
cx.runtime
|
||||
.any_memo((cx.id, id), |memo| memo.run((cx.id, id)));
|
||||
|
||||
eff
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Memo<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
runtime: &'static Runtime,
|
||||
pub(crate) scope: ScopeId,
|
||||
pub(crate) id: MemoId,
|
||||
pub(crate) ty: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for Memo<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
runtime: self.runtime,
|
||||
scope: self.scope,
|
||||
id: self.id,
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for Memo<T> {}
|
||||
|
||||
impl<T> Memo<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
pub fn get(&self) -> T
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.with(T::clone)
|
||||
}
|
||||
|
||||
pub fn with<U>(&self, f: impl Fn(&T) -> U) -> U {
|
||||
if let Some(running_subscriber) = self.runtime.running_effect() {
|
||||
match running_subscriber {
|
||||
Subscriber::Memo(running_memo_id) => {
|
||||
self.runtime.any_memo(running_memo_id, |running_memo| {
|
||||
self.add_subscriber(Subscriber::Memo(running_memo_id));
|
||||
running_memo.subscribe_to(Source::Memo((self.scope, self.id)));
|
||||
});
|
||||
}
|
||||
Subscriber::Effect(running_effect_id) => {
|
||||
self.runtime
|
||||
.any_effect(running_effect_id, |running_effect| {
|
||||
self.add_subscriber(Subscriber::Effect(running_effect_id));
|
||||
running_effect.subscribe_to(Source::Memo((self.scope, self.id)));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If transition is running, or contains this as a source, read from t_value
|
||||
if let Some(transition) = self.runtime.running_transition() {
|
||||
self.runtime
|
||||
.memo((self.scope, self.id), |state: &MemoState<T>| {
|
||||
if transition.running.get()
|
||||
&& transition.memos.borrow().contains(&(self.scope, self.id))
|
||||
{
|
||||
f(state
|
||||
.t_value
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.expect("read ReadSignal under transition, without any t_value"))
|
||||
} else {
|
||||
f(state.value.borrow().as_ref().unwrap())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.runtime.memo(
|
||||
(self.scope, self.id),
|
||||
|memo_state: &MemoState<T>| match &*memo_state.value.borrow() {
|
||||
Some(v) => f(v),
|
||||
None => {
|
||||
memo_state.run((self.scope, self.id));
|
||||
f(memo_state.value.borrow().as_ref().unwrap())
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_subscriber(&self, subscriber: Subscriber) {
|
||||
self.runtime
|
||||
.memo((self.scope, self.id), |memo_state: &MemoState<T>| {
|
||||
memo_state.subscribers.borrow_mut().insert(subscriber);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub(crate) struct MemoId(pub(crate) usize);
|
||||
|
||||
pub(crate) struct MemoState<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
runtime: &'static Runtime,
|
||||
f: Box<debug_cell::RefCell<dyn FnMut(Option<&T>) -> T>>,
|
||||
value: debug_cell::RefCell<Option<T>>,
|
||||
t_value: debug_cell::RefCell<Option<T>>,
|
||||
sources: debug_cell::RefCell<HashSet<Source>>,
|
||||
subscribers: debug_cell::RefCell<HashSet<Subscriber>>,
|
||||
}
|
||||
|
||||
impl<T> Debug for MemoState<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MemoState")
|
||||
.field(
|
||||
"f",
|
||||
&format!(
|
||||
"FnMut<Option<&{}>> -> {}",
|
||||
type_name::<T>(),
|
||||
type_name::<T>()
|
||||
),
|
||||
)
|
||||
.field("value", &*self.value.borrow())
|
||||
.field("t_value", &*self.t_value.borrow())
|
||||
.field("sources", &*self.sources.borrow())
|
||||
.field("subscribers", &*self.subscribers.borrow())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MemoState<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
pub fn new(runtime: &'static Runtime, f: impl FnMut(Option<&T>) -> T + 'static) -> Self {
|
||||
let f = Box::new(debug_cell::RefCell::new(f));
|
||||
|
||||
Self {
|
||||
runtime,
|
||||
f,
|
||||
value: debug_cell::RefCell::new(None),
|
||||
sources: Default::default(),
|
||||
t_value: Default::default(),
|
||||
subscribers: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_source(&self, source: Source) {
|
||||
self.sources.borrow_mut().insert(source);
|
||||
}
|
||||
|
||||
fn cleanup(&self, id: (ScopeId, MemoId)) {
|
||||
for source in self.sources.borrow().iter() {
|
||||
source.unsubscribe(self.runtime, Subscriber::Memo(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait AnyMemo: Debug {
|
||||
fn run(&self, id: (ScopeId, MemoId));
|
||||
|
||||
fn unsubscribe(&self, subscriber: Subscriber);
|
||||
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
fn subscribe_to(&self, source: Source);
|
||||
|
||||
fn end_transition(&self, runtime: &'static Runtime);
|
||||
}
|
||||
|
||||
impl<T> AnyMemo for MemoState<T>
|
||||
where
|
||||
T: Debug + 'static,
|
||||
{
|
||||
fn run(&self, id: (ScopeId, MemoId)) {
|
||||
// clear previous dependencies
|
||||
// at this point, Effect dependencies have been added to Signal
|
||||
// and any Signal changes will call Effect dependency automatically
|
||||
self.cleanup(id);
|
||||
|
||||
// add it to the Scope stack, which means any signals called
|
||||
// in the effect fn immediately below will add this Effect as a dependency
|
||||
self.runtime.push_stack(Subscriber::Memo(id));
|
||||
|
||||
// actually run the effect
|
||||
|
||||
if let Some(transition) = self.runtime.running_transition() {
|
||||
let mut t_value = self.t_value.borrow_mut();
|
||||
if let Some(t_value) = &mut *t_value {
|
||||
let v = { (self.f.borrow_mut())(Some(t_value)) };
|
||||
*t_value = v;
|
||||
} else {
|
||||
// fork reality, using the old value as the basis for the transitional value
|
||||
let v = { (self.f.borrow_mut())(self.value.borrow().as_ref()) };
|
||||
*t_value = Some(v);
|
||||
|
||||
// track this memo
|
||||
transition.memos.borrow_mut().insert(id);
|
||||
}
|
||||
} else {
|
||||
let v = { (self.f.borrow_mut())(self.value.borrow().as_ref()) };
|
||||
*self.value.borrow_mut() = Some(v);
|
||||
}
|
||||
|
||||
// notify subscribers
|
||||
let subs = { self.subscribers.borrow().clone() };
|
||||
for subscriber in subs.iter() {
|
||||
subscriber.run(self.runtime);
|
||||
}
|
||||
|
||||
// pop it back off the stack
|
||||
self.runtime.pop_stack();
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn subscribe_to(&self, source: Source) {
|
||||
self.add_source(source);
|
||||
}
|
||||
|
||||
fn unsubscribe(&self, subscriber: Subscriber) {
|
||||
self.subscribers.borrow_mut().remove(&subscriber);
|
||||
}
|
||||
|
||||
fn end_transition(&self, runtime: &'static Runtime) {
|
||||
let t_value = self.t_value.borrow_mut().take();
|
||||
|
||||
if let Some(value) = t_value {
|
||||
*self.value.borrow_mut() = Some(value);
|
||||
|
||||
let subs = { self.subscribers.borrow().clone() };
|
||||
for subscriber in subs.iter() {
|
||||
subscriber.run(runtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FnOnce<()> for Memo<T>
|
||||
where
|
||||
T: Debug + Clone,
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FnMut<()> for Memo<T>
|
||||
where
|
||||
T: Debug + Clone,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Fn<()> for Memo<T>
|
||||
where
|
||||
T: Debug + Clone,
|
||||
{
|
||||
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
|
||||
self.get()
|
||||
}
|
||||
read
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
AnyEffect, AnyMemo, AnySignal, EffectId, MemoId, MemoState, ResourceId, ResourceState, Scope,
|
||||
ScopeDisposer, ScopeId, ScopeState, SignalId, SignalState, Subscriber, TransitionState,
|
||||
AnyEffect, AnySignal, EffectId, ResourceId, ResourceState, Scope, ScopeDisposer, ScopeId,
|
||||
ScopeState, SignalId, SignalState, Subscriber, TransitionState,
|
||||
};
|
||||
use slotmap::SlotMap;
|
||||
use std::cell::RefCell;
|
||||
|
@ -43,32 +43,6 @@ impl Runtime {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn any_memo<T>(&self, id: (ScopeId, MemoId), f: impl FnOnce(&dyn AnyMemo) -> T) -> T {
|
||||
self.scope(id.0, |scope| {
|
||||
if let Some(n) = scope.memos.get(id.1 .0) {
|
||||
(f)(n)
|
||||
} else {
|
||||
panic!("couldn't locate {id:?}");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn memo<T, U>(&self, id: (ScopeId, MemoId), f: impl FnOnce(&MemoState<T>) -> U) -> U
|
||||
where
|
||||
T: Debug + 'static,
|
||||
{
|
||||
self.any_memo(id, |n| {
|
||||
if let Some(n) = n.as_any().downcast_ref::<MemoState<T>>() {
|
||||
f(n)
|
||||
} else {
|
||||
panic!(
|
||||
"couldn't convert {id:?} to MemoState<{}>",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn any_signal<T>(&self, id: (ScopeId, SignalId), f: impl FnOnce(&dyn AnySignal) -> T) -> T {
|
||||
self.scope(id.0, |scope| {
|
||||
if let Some(n) = scope.signals.get(id.1 .0) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
AnyEffect, AnyMemo, AnySignal, EffectId, EffectState, MemoId, MemoState, ReadSignal,
|
||||
ResourceId, ResourceState, Runtime, SignalId, SignalState, Transition,
|
||||
AnyEffect, AnySignal, EffectId, EffectState, ReadSignal, ResourceId, ResourceState, Runtime,
|
||||
SignalId, SignalState, Transition,
|
||||
};
|
||||
use elsa::FrozenVec;
|
||||
use serde::Serialize;
|
||||
|
@ -61,16 +61,6 @@ impl Scope {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn push_memo<T>(&self, state: MemoState<T>) -> MemoId
|
||||
where
|
||||
T: Debug + 'static,
|
||||
{
|
||||
self.runtime.scope(self.id, |scope| {
|
||||
scope.memos.push(Box::new(state));
|
||||
MemoId(scope.memos.len() - 1)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn push_resource<S, T>(&self, state: Rc<ResourceState<S, T>>) -> ResourceId
|
||||
where
|
||||
S: Debug + Clone + 'static,
|
||||
|
@ -114,7 +104,6 @@ pub(crate) struct ScopeState {
|
|||
pub(crate) contexts: debug_cell::RefCell<HashMap<TypeId, Box<dyn Any>>>,
|
||||
pub(crate) children: debug_cell::RefCell<Vec<ScopeId>>,
|
||||
pub(crate) signals: FrozenVec<Box<dyn AnySignal>>,
|
||||
pub(crate) memos: FrozenVec<Box<dyn AnyMemo>>,
|
||||
pub(crate) effects: FrozenVec<Box<dyn AnyEffect>>,
|
||||
pub(crate) resources: FrozenVec<Rc<dyn Any>>,
|
||||
}
|
||||
|
@ -132,7 +121,6 @@ impl ScopeState {
|
|||
contexts: Default::default(),
|
||||
children: Default::default(),
|
||||
signals: Default::default(),
|
||||
memos: Default::default(),
|
||||
effects: Default::default(),
|
||||
resources: Default::default(),
|
||||
}
|
||||
|
|
|
@ -50,21 +50,11 @@ where
|
|||
|
||||
pub fn with<U>(&self, f: impl Fn(&T) -> U) -> U {
|
||||
if let Some(running_subscriber) = self.runtime.running_effect() {
|
||||
match running_subscriber {
|
||||
Subscriber::Memo(running_memo_id) => {
|
||||
self.runtime.any_memo(running_memo_id, |running_memo| {
|
||||
self.add_subscriber(Subscriber::Memo(running_memo_id));
|
||||
running_memo.subscribe_to(Source::Signal((self.scope, self.id)));
|
||||
});
|
||||
}
|
||||
Subscriber::Effect(running_effect_id) => {
|
||||
self.runtime
|
||||
.any_effect(running_effect_id, |running_effect| {
|
||||
self.add_subscriber(Subscriber::Effect(running_effect_id));
|
||||
running_effect.subscribe_to(Source::Signal((self.scope, self.id)));
|
||||
});
|
||||
}
|
||||
}
|
||||
self.runtime
|
||||
.any_effect(running_subscriber.0, |running_effect| {
|
||||
self.add_subscriber(Subscriber(running_subscriber.0));
|
||||
running_effect.subscribe_to(Source((self.scope, self.id)));
|
||||
});
|
||||
}
|
||||
|
||||
// If transition is running, or contains this as a source, take from t_value
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
use crate::{MemoId, Runtime, ScopeId, SignalId, Subscriber};
|
||||
use crate::{Runtime, ScopeId, SignalId, Subscriber};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub(crate) enum Source {
|
||||
Signal((ScopeId, SignalId)),
|
||||
Memo((ScopeId, MemoId)),
|
||||
}
|
||||
pub(crate) struct Source(pub(crate) (ScopeId, SignalId));
|
||||
|
||||
impl Source {
|
||||
pub fn unsubscribe(&self, runtime: &'static Runtime, subscriber: Subscriber) {
|
||||
match self {
|
||||
Source::Signal(id) => {
|
||||
runtime.any_signal(*id, |signal_state| signal_state.unsubscribe(subscriber))
|
||||
}
|
||||
Source::Memo(id) => {
|
||||
runtime.any_memo(*id, |memo_state| memo_state.unsubscribe(subscriber))
|
||||
}
|
||||
}
|
||||
runtime.any_signal(self.0, |signal_state| signal_state.unsubscribe(subscriber))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
use crate::{EffectId, MemoId, Runtime, ScopeId};
|
||||
use crate::{EffectId, Runtime, ScopeId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub(crate) enum Subscriber {
|
||||
Memo((ScopeId, MemoId)),
|
||||
Effect((ScopeId, EffectId)),
|
||||
}
|
||||
pub(crate) struct Subscriber(pub(crate) (ScopeId, EffectId));
|
||||
|
||||
impl Subscriber {
|
||||
pub fn run(&self, runtime: &'static Runtime) {
|
||||
match self {
|
||||
Subscriber::Memo(id) => runtime.any_memo(*id, |memo| memo.run(*id)),
|
||||
Subscriber::Effect(id) => runtime.any_effect(*id, |effect| effect.run(*id)),
|
||||
}
|
||||
runtime.any_effect(self.0, |effect| effect.run(self.0))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
create_effect, create_signal, runtime::Runtime, spawn::queue_microtask, EffectId, MemoId,
|
||||
ReadSignal, Scope, ScopeId, SignalId, WriteSignal,
|
||||
create_effect, create_signal, runtime::Runtime, spawn::queue_microtask, EffectId, ReadSignal,
|
||||
Scope, ScopeId, SignalId, WriteSignal,
|
||||
};
|
||||
|
||||
pub fn use_transition(cx: Scope) -> Transition {
|
||||
|
@ -38,7 +38,6 @@ impl Transition {
|
|||
running: Cell::new(true),
|
||||
resources: Default::default(),
|
||||
signals: Default::default(),
|
||||
memos: Default::default(),
|
||||
effects: Default::default(),
|
||||
}));
|
||||
}
|
||||
|
@ -52,7 +51,6 @@ impl Transition {
|
|||
let scope = self.scope;
|
||||
let resources = running_transition.resources.clone();
|
||||
let signals = running_transition.signals.clone();
|
||||
let memos = running_transition.memos.clone();
|
||||
let effects = running_transition.effects.clone();
|
||||
let set_pending = self.set_pending;
|
||||
// place this at end of task queue so it doesn't start at 0
|
||||
|
@ -66,11 +64,6 @@ impl Transition {
|
|||
signal.end_transition(runtime);
|
||||
});
|
||||
}
|
||||
for memo in memos.borrow().iter() {
|
||||
runtime.any_memo(*memo, |memo| {
|
||||
memo.end_transition(runtime);
|
||||
});
|
||||
}
|
||||
for effect in effects.borrow().iter() {
|
||||
runtime.any_effect(*effect, |any_effect| {
|
||||
any_effect.run(*effect);
|
||||
|
@ -94,6 +87,5 @@ pub(crate) struct TransitionState {
|
|||
pub running: Cell<bool>,
|
||||
pub resources: Rc<RefCell<HashSet<ReadSignal<usize>>>>,
|
||||
pub signals: Rc<RefCell<HashSet<(ScopeId, SignalId)>>>,
|
||||
pub memos: Rc<RefCell<HashSet<(ScopeId, MemoId)>>>,
|
||||
pub effects: Rc<RefCell<Vec<(ScopeId, EffectId)>>>,
|
||||
}
|
||||
|
|
|
@ -51,10 +51,10 @@ where
|
|||
// Rebuild the list of nested routes conservatively, and show the root route here
|
||||
let mut disposers = Vec::<ScopeDisposer>::new();
|
||||
|
||||
let route_states: Memo<RouterState> = create_memo(cx, move |prev: Option<&RouterState>| {
|
||||
let route_states: Memo<RouterState> = create_memo(cx, move |prev: Option<RouterState>| {
|
||||
let next_matches = matches();
|
||||
let prev_matches = prev.map(|p| &p.matches);
|
||||
let prev_routes = prev.map(|p| &p.routes);
|
||||
let prev_matches = prev.as_ref().map(|p| &p.matches);
|
||||
let prev_routes = prev.as_ref().map(|p| &p.routes);
|
||||
|
||||
// are the new route matches the same as the previous route matches so far?
|
||||
let mut equal = prev_matches
|
||||
|
@ -107,7 +107,7 @@ where
|
|||
|
||||
// TODO dispose of extra routes from previous matches if they're longer than new ones
|
||||
|
||||
if let Some(prev) = prev && equal {
|
||||
if let Some(prev) = &prev && equal {
|
||||
RouterState {
|
||||
matches: next_matches.to_vec(),
|
||||
routes: prev_routes.cloned().unwrap_or_default(),
|
||||
|
@ -139,7 +139,7 @@ where
|
|||
view! { <div>{root_outlet}</div> }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct RouterState {
|
||||
matches: Vec<RouteMatch>,
|
||||
routes: Rc<RefCell<Vec<RouteContext>>>,
|
||||
|
|
|
@ -5,14 +5,14 @@ use crate::{State, Url};
|
|||
use super::params::ParamsMap;
|
||||
|
||||
pub fn create_location(cx: Scope, path: ReadSignal<String>, state: ReadSignal<State>) -> Location {
|
||||
let url = create_memo(cx, move |prev: Option<&Url>| {
|
||||
let url = create_memo(cx, move |prev: Option<Url>| {
|
||||
path.with(|path| {
|
||||
log::debug!("create_location with path {path}");
|
||||
match Url::try_from(path.as_str()) {
|
||||
Ok(url) => url,
|
||||
Err(e) => {
|
||||
log::error!("[Leptos Router] Invalid path {path}\n\n{e:?}");
|
||||
prev.unwrap().clone()
|
||||
prev.clone().unwrap()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue