Skip to content

Commit

Permalink
fix: do not use stale values in AsyncDerived if it is mutated before …
Browse files Browse the repository at this point in the history
…running (leptos-rs#3475)
  • Loading branch information
gbj authored Jan 14, 2025
1 parent 62196ff commit a9ce608
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 6 deletions.
2 changes: 1 addition & 1 deletion leptos_macro/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1651,7 +1651,7 @@ pub(crate) fn ident_from_tag_name(tag_name: &NodeName) -> Ident {
.path
.segments
.iter()
.last()
.next_back()
.map(|segment| segment.ident.clone())
.expect("element needs to have a name"),
NodeName::Block(_) => {
Expand Down
21 changes: 16 additions & 5 deletions reactive_graph/src/computed/async_derived/arc_async_derived.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,10 @@ macro_rules! spawn_derived {
// so that the correct value is set synchronously
let initial = initial_fut.as_mut().now_or_never();
match initial {
None => (false, Some(initial_fut)),
None => {
inner.write().or_poisoned().notifier.notify();
(false, Some(initial_fut))
}
Some(orig_value) => {
let mut guard = this.inner.write().or_poisoned();

Expand All @@ -296,10 +299,6 @@ macro_rules! spawn_derived {
if was_ready {
first_run.take();
}
// begin loading eagerly but asynchronously, if not already loaded
if !was_ready {
any_subscriber.mark_dirty();
}

if let Some(source) = $source {
any_subscriber.with_observer(|| source.track());
Expand All @@ -312,6 +311,18 @@ macro_rules! spawn_derived {
let wakers = Arc::downgrade(&this.wakers);
let loading = Arc::downgrade(&this.loading);
let fut = async move {
// if the AsyncDerived has *already* been marked dirty (i.e., one of its
// sources has changed after creation), we should throw out the Future
// we already created, because its values might be stale
let already_dirty = inner.upgrade()
.as_ref()
.and_then(|inner| inner.read().ok())
.map(|inner| inner.state == AsyncDerivedState::Dirty)
.unwrap_or(false);
if already_dirty {
initial_fut.take();
}

while rx.next().await.is_some() {
let update_if_necessary = if $should_track {
any_subscriber
Expand Down

0 comments on commit a9ce608

Please sign in to comment.