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
Then I see c-result has the text 0
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
Then I see c-result has the text 1

View File

@@ -134,7 +134,7 @@ where
}
});
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, _, _> {
id,

View File

@@ -117,7 +117,7 @@ where
}
});
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 {
Effect::new_isomorphic({
let none_pending = none_pending.clone();

View File

@@ -15,7 +15,7 @@ use codee::{
Decoder, Encoder,
};
use core::{fmt::Debug, marker::PhantomData};
use futures::Future;
use futures::{Future, FutureExt};
use or_poisoned::OrPoisoned;
use reactive_graph::{
computed::{
@@ -258,11 +258,17 @@ where
if let Some(suspense_context) = use_context::<SuspenseContext>() {
if self.value.read().or_poisoned().is_none() {
let handle = suspense_context.task_id();
let ready = SpecialNonReactiveFuture::new(self.ready());
reactive_graph::spawn(async move {
ready.await;
drop(handle);
});
let mut ready =
Box::pin(SpecialNonReactiveFuture::new(self.ready()));
match ready.as_mut().now_or_never() {
Some(_) => drop(handle),
None => {
reactive_graph::spawn(async move {
ready.await;
drop(handle);
});
}
}
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> {
if let Some(suspense_context) = use_context::<SuspenseContext>() {
// create a handle to register it with suspense
let handle = suspense_context.task_id();
let ready = SpecialNonReactiveFuture::new(self.ready());
crate::spawn(async move {
ready.await;
drop(handle);
});
// check if the task is *already* ready
let mut ready =
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
.write()
.or_poisoned()