DioxusLabs / dioxus

Fullstack GUI library for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
19.3k stars 735 forks source link

Hot reloading panics #2238

Closed Dimchikkk closed 2 months ago

Dimchikkk commented 2 months ago

Problem

Hot reloading panics:

panicked at ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/dioxus-core-0.5.0/src/arena.rs:57:32: cannot reclaim ElementId(9)

Steps To Reproduce

Steps to reproduce the behavior:

#![allow(non_snake_case)]

use dioxus::prelude::*;
use log::LevelFilter;

fn main() {
    // Init debug
    dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
    console_error_panic_hook::set_once();

    launch(SplashScreen);
}

#[component]
fn SplashScreen() -> Element {
    rsx! {
        div {
            width: "100%",
            justify_content: "center",
            align_items: "center",
            div {
                width: 100,
                height: 100,
                div {
                    width: "100%",
                    height: "100%",
                    align_items: "center",
                    padding: 48,
                    justify_content: "space_around",
                    Footer {}
                }
                h1 { "Modify it" },
            }
        }
    }
}

#[component]
fn Footer() -> Element {
    rsx! {
        div {
            div {
                width: 100,
                border: 1,
                border_color: "#090a0b",
                h1 { "Footer 1" }
            }
            div {
                margin: "0 0 24px 0",
                width: 100,
                gap: 20,
                justify_content: "center",
                align_items: "center",
                h1 { "Footer 2" }
            }
        }
    }
}

dx serve

Change "Modify it" text to anything.

Expected behavior

Hot-reloading picks up the text changes.

Screenshots

Screenshot 2024-04-04 at 13 21 30

Environment:

Note

If footer code changed to the following code:

#[component]
fn Footer() -> Element {
    rsx! {
        div {
            div {
                width: 100,
                border: 1,
                border_color: "#090a0b",
                h1 { "Footer 1" }
            }
            div {
                margin: "0 0 24px 0",
                width: 99,
                gap: 20,
                justify_content: "center",
                align_items: "center",
                h1 { "Footer 2" }
            }
        }
    }
}

(notice divs have different width values)

hot reloading works as expected.

//cc @ickshonpe

jremb commented 2 months ago

I'm able to reproduce your crash, but only on the second modification reload. I'm having a similar experience with dynamically rendering an element and hot reloading crashing on the second toggle. This does not occur with the target build (cargo build --release).

If I strip out the inline CSS from your example, the problem disappears:

#![allow(non_snake_case)]

use dioxus::prelude::*;
use log::LevelFilter;

fn main() {
    // Init debug
    dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
    console_error_panic_hook::set_once();

    launch(SplashScreen);
}

#[component]
fn SplashScreen() -> Element {
    rsx! {
        div {
            div {
                div {
                    Footer {}
                }
                h1 { "sssss sit" },
            }
        }
    }
}

#[component]
fn Footer() -> Element {
    rsx! {
        div {
            div {
                h1 { "Footer 1" }
            }
            div {
                h1 { "Footer 2" }
            }
        }
    }
}

As for my own case, I'm using a vanilla style sheet in the assets directory. I tried to come up with a simple example, but couldn't reproduce it.

So this works fine hot reloading:

#![allow(non_snake_case)]

use dioxus::prelude::*;
use log::LevelFilter;

#[derive(Clone, Routable, Debug, PartialEq)]
enum Route {
    #[route("/")]
    Home {},
}

fn main() {
    // Init debug
    dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");

    dioxus::launch(App);
}

#[component]
fn App() -> Element {
    rsx! {
        Router::<Route> {}
    }
}

#[derive(Props, Clone, PartialEq)]
struct LoginProp {
    logged_in: bool,
}

#[component]
fn LoginComponent(props: LoginProp) -> Element {
    let LoginProp { logged_in } = props;
    if !logged_in {
        return None;
    }
    rsx! { 
        p { class: "p-class", "You are logged in" }
    }
}

#[component]
fn Home() -> Element {
    let mut logged_in = use_signal(||false);

    rsx! {
        LoginComponent { logged_in: logged_in() }
        button { 
            class: "button-class",
            onclick: move |_| logged_in.toggle(),
            "Log in",
        }
    }
}

But my actual use case which involves a similar but more complex setup for hiding a sidebar crashes. Removing the style sheet didn't solve the issue.

Environment: