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:
#![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<i32>) -> 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
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:
Expected behavior
The effect should only rerun when
signal_achanges. 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 listEnvironment: