mirror of
https://github.com/leptos-rs/leptos
synced 2024-09-20 14:32:00 +00:00
distinguish between dirty and check in effects, so that memos and signals both work correctly
This commit is contained in:
parent
8385287123
commit
1a739015e1
3 changed files with 37 additions and 31 deletions
|
@ -35,6 +35,7 @@ fn effect_base() -> (Receiver, Owner, Arc<RwLock<EffectInner>>) {
|
|||
|
||||
let owner = Owner::new();
|
||||
let inner = Arc::new(RwLock::new(EffectInner {
|
||||
dirty: true,
|
||||
observer,
|
||||
sources: SourceSet::new(),
|
||||
}));
|
||||
|
|
|
@ -9,6 +9,7 @@ use or_poisoned::OrPoisoned;
|
|||
use std::sync::{Arc, RwLock, Weak};
|
||||
|
||||
pub(crate) struct EffectInner {
|
||||
pub dirty: bool,
|
||||
pub observer: Sender,
|
||||
pub sources: SourceSet,
|
||||
}
|
||||
|
@ -25,14 +26,18 @@ impl ToAnySubscriber for Arc<RwLock<EffectInner>> {
|
|||
impl ReactiveNode for RwLock<EffectInner> {
|
||||
fn mark_subscribers_check(&self) {}
|
||||
|
||||
// TODO check if this actually works for memos
|
||||
fn update_if_necessary(&self) -> bool {
|
||||
let sources = {
|
||||
let guard = self.read().or_poisoned();
|
||||
guard.sources.clone()
|
||||
};
|
||||
let mut guard = self.write().or_poisoned();
|
||||
let (is_dirty, sources) =
|
||||
(guard.dirty, (!guard.dirty).then(|| guard.sources.clone()));
|
||||
|
||||
for source in sources {
|
||||
if is_dirty {
|
||||
guard.dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
drop(guard);
|
||||
for source in sources.into_iter().flatten() {
|
||||
if source.update_if_necessary() {
|
||||
return true;
|
||||
}
|
||||
|
@ -45,7 +50,9 @@ impl ReactiveNode for RwLock<EffectInner> {
|
|||
}
|
||||
|
||||
fn mark_dirty(&self) {
|
||||
self.write().or_poisoned().observer.notify()
|
||||
let mut lock = self.write().or_poisoned();
|
||||
lock.dirty = true;
|
||||
lock.observer.notify()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,39 +47,37 @@ where
|
|||
let value = Arc::new(RwLock::new(None::<T>));
|
||||
let owner = Owner::new();
|
||||
let inner = Arc::new(RwLock::new(EffectInner {
|
||||
dirty: false,
|
||||
observer,
|
||||
sources: SourceSet::new(),
|
||||
}));
|
||||
|
||||
#[cfg(feature = "effects")]
|
||||
{
|
||||
let initial_value = Some(owner.with(|| {
|
||||
inner
|
||||
.to_any_subscriber()
|
||||
.with_observer(|| fun(initial_value))
|
||||
}));
|
||||
*value.write().or_poisoned() = initial_value;
|
||||
let initial_value = Some(owner.with(|| {
|
||||
inner
|
||||
.to_any_subscriber()
|
||||
.with_observer(|| fun(initial_value))
|
||||
}));
|
||||
*value.write().or_poisoned() = initial_value;
|
||||
|
||||
Executor::spawn_local({
|
||||
let value = Arc::clone(&value);
|
||||
let subscriber = inner.to_any_subscriber();
|
||||
Executor::spawn_local({
|
||||
let value = Arc::clone(&value);
|
||||
let subscriber = inner.to_any_subscriber();
|
||||
|
||||
async move {
|
||||
while rx.next().await.is_some() {
|
||||
if subscriber.update_if_necessary() {
|
||||
subscriber.clear_sources(&subscriber);
|
||||
async move {
|
||||
while rx.next().await.is_some() {
|
||||
if subscriber.update_if_necessary() {
|
||||
subscriber.clear_sources(&subscriber);
|
||||
|
||||
let old_value =
|
||||
mem::take(&mut *value.write().or_poisoned());
|
||||
let new_value = owner.with_cleanup(|| {
|
||||
subscriber.with_observer(|| fun(old_value))
|
||||
});
|
||||
*value.write().or_poisoned() = Some(new_value);
|
||||
}
|
||||
let old_value =
|
||||
mem::take(&mut *value.write().or_poisoned());
|
||||
let new_value = owner.with(|| {
|
||||
subscriber.with_observer(|| fun(old_value))
|
||||
});
|
||||
*value.write().or_poisoned() = Some(new_value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
RenderEffect { value, inner }
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue