schedule_update is insufficently documented and causes unexpected invalidation
Problem
The docs for schedule_update just describe it as:
Schedule an update for the current component
My expectation based on on this (and its use in https://dioxuslabs.com/learn/0.6/cookbook/state/custom_hooks/ ) is that calling the returned function will invalidate the current rendering of the current context.
Based on experimentation, this is not how it behaves. Instead it invalidates what ever version of the component is current when the callback is called (not what was current when schedule_update was called).
Steps To Reproduce
Steps to reproduce the behavior:
- Drop the code from https://gist.github.com/Craig-Macomber/6d7d4aaea5b1225d092a62477ad0cb4f into some example app, like examples/hello_world.rs and run it.
- Click the "Click First" button, then immediately click the "Click Second" button.
- Wait 5 seconds
- Observe the log It should look something like:
2025-05-14T04:39:31.138084Z INFO hello_world: App evaluated! 2025-05-14T04:39:31.138129Z INFO hello_world: Observing slow signal 2025-05-14T04:39:32.711087Z INFO hello_world: Clicked First 2025-05-14T04:39:33.622360Z INFO hello_world: Clicked Second 2025-05-14T04:39:33.622390Z INFO hello_world: Writing to fast signal. This causes re-render which does not observe slow signal. 2025-05-14T04:39:33.622550Z INFO hello_world: App evaluated! 2025-05-14T04:39:33.622567Z INFO hello_world: Skipped observing slow signal: writes to the slow signal should no longer cause invalidation. 2025-05-14T04:39:37.712477Z INFO hello_world: Writing to slow signal. This should not cause invalidation if slow signal was not observed. 2025-05-14T04:39:37.712570Z INFO hello_world: App evaluated! 2025-05-14T04:39:37.712584Z INFO hello_world: Skipped observing slow signal: writes to the slow signal should no longer cause invalidation.
Expected behavior
The last two log lines should not be printed, since the write to the slow signal should not cause any invalidation since the signal was not observed on the latest render.
Environment:
- Dioxus version: 0.6.3 and main (at e47d0aa86838ec757405801fc75bf05646205a03 )
- Rust version: rustc 1.85.0 (4d91de4e4 2025-02-17)
- OS info: Linux
- App platform: Desktop and web
Proposed solutions
Either document this as expected behavior and add an alternative without the additional invalidation, or remove the extra invalidation.
My gist includes a fixed version. This was based on the actual implementation of signals, which do not have this problem (unlike the example signals from https://dioxuslabs.com/learn/0.6/cookbook/state/custom_hooks/ which do).
Note that while I have confirmed this implementation does not have the issue this bug is about, I'm not confident its correct in other aspects.
fn schedule_update_fixed() -> Arc<dyn Fn() + Send + Sync> {
let subscribers: Arc<std::sync::Mutex<std::collections::HashSet<ReactiveContext>>> =
Default::default();
if let Some(reactive_context) = ReactiveContext::current() {
reactive_context.subscribe(subscribers.clone());
}
let callback = move || {
for reactive_context in subscribers.lock().unwrap().iter() {
reactive_context.mark_dirty();
}
};
Arc::new(callback)
}
On a related note, I searched the repo, and there does not seem to be a single use, not even a test or example using schedule_update. That seems a bit odd for something prominent enough to be included in the prelude.
This is expected behavior for schedule_update. It returns a callback for the currently running component that can be used to schedule a rerun in the future. The version of signals implemented in the custom hooks section is intentionally simplified and won't behave like the full signals implementation in all cases. We should probably change the example to use ReactiveContext instead which should be preferred in general over schedule_update because it works with other reactive contexts like memos, resources, and effects
Thanks for clarifying the expected behavior!
When I get a chance (in a few days probably), I can prepare PRs for:
- Alternative code for the hook example using reactive contexts. PR
- An update to the doc string for
schedule_updatePR
If you would like I would also be happy to author PRs for these as well:
- removing
schedule_updatefrom the prelude. Not sure if this is desired, might make sense to land in 7.0 if we want to reduce focus on it. PR - Adding an alternative to schedule_update (maybe schedule_invalidation?) using reactive contexts which only invalidates the current version of the component (I already have this code, so I might as well make it available if its desired)