this wasn't a bad idea, but I should implement it correctly

This commit is contained in:
Greg Johnston
2025-12-17 17:14:42 -05:00
parent 342445e8ac
commit 1fe838940d
5 changed files with 37 additions and 14 deletions

View File

@@ -33,6 +33,6 @@ Feature: Regression test for issue #4492
When I click the button c-toggle When I click the button c-toggle
Then I see c-result has the text 0 Then I see c-result has the text 0
When I click the button c-button When I click the button c-button
Then I see c-result has the text 0 Then I see c-result has the text 42
When I wait 100ms When I wait 100ms
Then I see c-result has the text 1 Then I see c-result has the text 1

View File

@@ -134,7 +134,7 @@ where
} }
}); });
let has_tasks = let has_tasks =
Arc::new(move || tasks.with_untracked(SlotMap::is_empty)); Arc::new(move || !tasks.with_untracked(SlotMap::is_empty));
OwnedView::new(SuspenseBoundary::<false, _, _> { OwnedView::new(SuspenseBoundary::<false, _, _> {
id, id,

View File

@@ -117,7 +117,7 @@ where
} }
}); });
let has_tasks = let has_tasks =
Arc::new(move || tasks.with_untracked(SlotMap::is_empty)); Arc::new(move || !tasks.with_untracked(SlotMap::is_empty));
if let Some(set_pending) = set_pending { if let Some(set_pending) = set_pending {
Effect::new_isomorphic({ Effect::new_isomorphic({
let none_pending = none_pending.clone(); let none_pending = none_pending.clone();

View File

@@ -15,7 +15,7 @@ use codee::{
Decoder, Encoder, Decoder, Encoder,
}; };
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData};
use futures::Future; use futures::{Future, FutureExt};
use or_poisoned::OrPoisoned; use or_poisoned::OrPoisoned;
use reactive_graph::{ use reactive_graph::{
computed::{ computed::{
@@ -258,11 +258,17 @@ where
if let Some(suspense_context) = use_context::<SuspenseContext>() { if let Some(suspense_context) = use_context::<SuspenseContext>() {
if self.value.read().or_poisoned().is_none() { if self.value.read().or_poisoned().is_none() {
let handle = suspense_context.task_id(); let handle = suspense_context.task_id();
let ready = SpecialNonReactiveFuture::new(self.ready()); let mut ready =
reactive_graph::spawn(async move { Box::pin(SpecialNonReactiveFuture::new(self.ready()));
ready.await; match ready.as_mut().now_or_never() {
drop(handle); Some(_) => drop(handle),
}); None => {
reactive_graph::spawn(async move {
ready.await;
drop(handle);
});
}
}
self.suspenses.write().or_poisoned().push(suspense_context); self.suspenses.write().or_poisoned().push(suspense_context);
} }
} }

View File

@@ -632,12 +632,29 @@ impl<T: 'static> ReadUntracked for ArcAsyncDerived<T> {
fn try_read_untracked(&self) -> Option<Self::Value> { fn try_read_untracked(&self) -> Option<Self::Value> {
if let Some(suspense_context) = use_context::<SuspenseContext>() { if let Some(suspense_context) = use_context::<SuspenseContext>() {
// create a handle to register it with suspense
let handle = suspense_context.task_id(); let handle = suspense_context.task_id();
let ready = SpecialNonReactiveFuture::new(self.ready());
crate::spawn(async move { // check if the task is *already* ready
ready.await; let mut ready =
drop(handle); Box::pin(SpecialNonReactiveFuture::new(self.ready()));
}); match ready.as_mut().now_or_never() {
Some(_) => {
// if it's already ready, drop the handle immediately
// this will immediately notify the suspense context that it's complete
drop(handle);
}
None => {
// otherwise, spawn a task to wait for it to be ready, then drop the handle,
// which will notify the suspense
crate::spawn(async move {
ready.await;
drop(handle);
});
}
}
// register the suspense context with our list of them, to be notified later if this re-runs
self.inner self.inner
.write() .write()
.or_poisoned() .or_poisoned()