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

Reading a resource breaks reactivity #2225

Closed thorn132 closed 2 months ago

thorn132 commented 2 months ago

Problem

Reading a resource (e.g. by res.read(), res.value(), or res.state()) breaks reactivity on the component that performed the read.

Steps To Reproduce

#[component]
fn App() -> Element {
    let mut x = use_signal(|| 0);

    let res = use_resource(move || {
        println!("resource triggered {}", x());
        async move { x() }
    });

    use_effect(move || println!("effect triggered {}", x()));

    // println!("resource state {:?}", res.state());
    // println!("resource value {:?}", res.value());
    // println!("resource read {:?}", res.read());

    rsx! {
        button {
            onclick: move |_| x += 1,
            "Trigger"
        }
    }
}

Un-comment any of the uses of res to enable the bug.

Expected behavior

When res is not used, the console output with N button clicks will be:

resource triggered 0
effect triggered 0
resource triggered 1
effect triggered 1
...
resource triggered N
effect triggered N

When all uses of res are un-commented, it is instead:

resource triggered 0
resource state Pending
resource value None
resource read None
resource state Ready
resource value Some(0)
resource read Some(0)

where clicking the button has no effect.

The use_effect on the signal x still breaks even if res does not use x.

Environment:

ealmloff commented 2 months ago

It seems like the duration of the future matters here. This code works as expected:

fn app() -> Element {
    let mut x = use_signal(|| 0);

    let res = use_resource(move || {
        println!("resource triggered {}", x());
        async move {
            tokio::time::sleep(std::time::Duration::from_millis(1)).await;
            x()
        }
    });

    use_effect(move || println!("effect triggered {}", x()));

    println!("resource state {:?}", res.state());
    println!("resource value {:?}", res.value());
    println!("resource read {:?}", res.read());

    rsx! {
        button {
            onclick: move |_| x += 1,
            "Trigger"
        }
    }
}