DioxusLabs / dioxus

Fullstack app framework for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
20.49k stars 788 forks source link

Crash when writing to signal from hook #2060

Closed jonnyandrew closed 6 months ago

jonnyandrew commented 6 months ago

Problem

When I write to a signal from within a use_effect hook, my app crashes.

The error is something like:

[Error] TypeError: undefined is not an object (evaluating 'templates[u16buf[u16bufp++]][u16buf[u16bufp++]]')
    run (index.html:1038:287)
    run_from_bytes (index.html:1047)
    (anonymous function) (index.html:1060)

Steps To Reproduce

Run the following minimal sample and look in the webview logs for the error.

#![allow(non_snake_case)]
use dioxus::prelude::*;

type App = String;

fn main() {
    launch(Root);
}

fn Root() -> Element {
    let app = use_signal(|| None::<App>);
    use_future(move || {
        to_owned![app];
        async move {
            *app.write() = Some(App::from("Fake app!"));
        }
    });

    let strings = use_signal(|| vec!["Initial string".to_owned()]);

    let app = &*app.read();
    match app {
        Some(_) => rsx! {
            div { "App is loaded." }
            Screen {
                strings: strings
            }
        },
        None => rsx! {
            div { "Loading app..." }
        },
    }
}

#[component]
fn Screen(strings: Signal<Vec<String>>) -> Element {
    // THIS LINE CAUSES A CRASH
    use_effect(move || {
        to_owned![strings];
        *strings.write() = vec![String::from("Loaded a string")]
    });
    rsx! {
        ListView {
            strings: strings
        }
    }
}

#[component]
fn ListView(strings: ReadOnlySignal<Vec<String>>) -> Element {
    rsx! {
        for string in strings.iter() {
            div {
                key: "{string}",
                "{string}"
            }
        }
    }
}

Expected behavior

It runs without crashing.

Screenshots N/A

Environment:

Questionnaire

jkelleyrtp commented 6 months ago

HI, this was fixed in #2022. Your code technically shouldn't have compiled:

Screenshot 2024-03-15 at 8 21 29 PM

With signals, you no longer need to call to_owned on values anymore, so your code can be simply rewritten to

use_effect(move || strings.set(vec![String::from("Loaded a string")]));