DioxusLabs / DioxusLabs/dioxus
ReadSignal coercion can cause extra reruns
- Dominant language
- Rust
- Stars
- 39.1k
- Forks
- 1.9k
- Avg merge
- 4d 10h
- Merged PRs (30d)
- 4
Description
**Problem**
When read signal swaps in place, it transfers more subscribers than it should which can cause scopes that subscribe to the old signal before coercion to rerun when the new signal changes
**Steps To Reproduce**
Run this example and follow the steps in the description:
```rust
#![allow(non_snake_case)]
use dioxus::prelude::*;
fn main() {
dioxus::launch(app);
}
fn app() -> Element {
let mut use_b = use_signal(|| false);
let mut effect_runs = use_signal(|| 0);
let mut signal_a = use_signal(|| 0);
let mut signal_b = use_signal(|| 0);
use_effect(move || {
let value = signal_a();
let runs = {
let mut write = effect_runs.write();
*write += 1;
*write
};
println!("parent effect ran: A = {value}, runs = {runs}");
});
let child_signal = if use_b() { signal_b } else { signal_a };
rsx! {
div {
max_width: "52rem",
margin: "0 auto",
padding: "2rem",
font_family: "sans-serif",
h1 { "Mapped ReadSignal point_to repro" }
p {
"Steps: leave A and B equal, swap the child from A to B, then increment B. "
"The parent effect below only reads A, so its run count should not change when B changes."
}
div {
display: "flex",
gap: "0.75rem",
flex_wrap: "wrap",
margin_bottom: "1rem",
button {
onclick: move |_| use_b.set(false),
"Child uses A"
}
button {
onclick: move |_| use_b.set(true),
"Child uses B"
}
button {
onclick: move |_| signal_a += 1,
"Increment A"
}
button {
onclick: move |_| signal_b += 1,
"Increment B"
}
button {
onclick: move |_| {
signal_a.set(0);
signal_b.set(0);
use_b.set(false);
effect_runs.set(0);
},
"Reset"
}
}
ul {
li { "Parent effect runs: {effect_runs}" }
li { "A: {signal_a}" }
li { "B: {signal_b}" }
li {
"Child source: "
if use_b() { "B" } else { "A" }
}
}
Child { sig: child_signal }
}
}
}
#[component]
fn Child(sig: ReadSignal) -> Element {
rsx! {
div {
margin_top: "1rem",
padding: "1rem",
border: "1px solid #ccc",
border_radius: "8px",
"Child value: {sig}"
}
}
}
```
**Expected behavior**
The effect should only rerun when `signal_a` changes. I think we can fix this issue by keeping a separate layer of subscribers for readsignal and only moving those subscribers instead of the whole list
**Environment:**
- Dioxus version: main
- Rust version: nightly
- OS info: macos
- App platform: all
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.