dioxus
dioxus copied to clipboard
Diffing bug
Problem
https://discord.com/channels/899851952891002890/943190605067079712/1229957121496580197
With the below code it recreates the ListTest
component when ListTest2
goes back to its initial state.
As in if it started with a % 3 == 0
then it recreates it every time a % 3 == 0
Steps To Reproduce
use dioxus::prelude::*;
#[component]
pub fn App() -> Element {
let mut b = use_signal(|| 0);
rsx! {
ListTest2 {
a: b()
}
button {
onclick: move |_| b += 1,
"+"
}
button {
onclick: move |_| b -= 1,
"-"
}
}
}
#[component]
pub fn ListTest2(a: u32) -> Element {
rsx! {
if a % 3 == 0 {
ListTest {
test: 4u32,
b:4u32,
c:6u32
}
} else if a % 3 == 1 {
ListTest {
test: 5u32,
b:6u32,
c:6u32
}
} else {
ListTest {
test: 3u32,
b:3u32,
c:6u32
}
}
}
}
#[component]
pub fn ListTest(test: ReadOnlySignal<u32>, b: u32, c: u32) -> Element {
use_hook(|| log::info!("{test}, {b}, {c}"));
rsx! {
{test().to_string()}
{b.to_string()}
{c.to_string()}
}
}
Expected behavior
The way i had it explained to me is that it shouldnt recreate the component at all with the above code
Environment:
- Dioxus version: 0.51
- Rust version: 1.76.0
- OS info: MacOS
- App platform: Web
Questionnaire
- [ ] I'm interested in fixing this myself but don't know where to start
- [ ] I would like to fix and I have a solution
- [ ] I don't have time to fix this right now, but maybe later
Right now we do swap templates completely depending on the unique ID of every macro call. I believe there's a comment in the codebase to that effect too, though in this particular instance tossing a few checks in wouldn't terribly large overhead so we could support this usecase.
You could, if you wanted, drive the props from the conditional and pass it into a single rsx! call which won't swap templates between renders.
We don't guarantee this behavior, but I think this should be handled by light_diff_template. That code doesn't seem to be working correctly
I can no longer reproduce the issue with this code on the main branch of dioxus:
use dioxus::prelude::*;
fn main() {
tracing_subscriber::fmt::init();
launch(app);
}
#[component]
pub fn app() -> Element {
let mut b = use_signal(|| 0);
rsx! {
ListTest2 {
a: b()
}
button {
onclick: move |_| b += 1,
"+"
}
button {
onclick: move |_| b -= 1,
"-"
}
}
}
#[component]
pub fn ListTest2(a: u32) -> Element {
rsx! {
if a % 3 == 0 {
ListTest {
test: 4u32,
b:4u32,
c:6u32
}
} else if a % 3 == 1 {
ListTest {
test: 5u32,
b:6u32,
c:6u32
}
} else {
ListTest {
test: 3u32,
b:3u32,
c:6u32
}
}
}
}
#[component]
pub fn ListTest(test: ReadOnlySignal<u32>, b: u32, c: u32) -> Element {
use_hook(|| tracing::info!("{test}, {b}, {c}"));
rsx! {
{test().to_string()}
{b.to_string()}
{c.to_string()}
}
}