DioxusLabs / dioxus

Fullstack app framework for web, desktop, mobile, and more.

Home Page:https://dioxuslabs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`use_effect` not running when writing to signal asynchronously

pablosichert opened this issue · comments

Heyo,

thank you for this great library! I'm having a problem with signals that I reduced to a minimal example.

I want to run a side effect within a use_effect that is derived from a signal. The signal itself is not used for rendering.

When writing to this signal asynchronously, I can not get it to fire consistently (it works sometimes, but very rarely).

Steps To Reproduce

Cargo.toml
[package]
name = "signal_asynchronous_write_not_rerendering"
version = "0.0.0"
edition = "2021"

[dependencies]
dioxus = { version = "0.5", features = ["fullstack"] }
log = "0.4"
dioxus-logger = "0.4"
wasm-bindgen-futures = "0.4"
web-sys = "0.3"

[features]
default = []
server = ["dioxus/axum"]
web = ["dioxus/web"]
main.rsExpand to see full file
use dioxus::prelude::*;
use log::LevelFilter;
use wasm_bindgen_futures::JsFuture;
use web_sys::{
    js_sys::{Function, Promise},
    window,
};

fn main() {
    dioxus_logger::init(LevelFilter::Debug).unwrap();
    launch(App);
}

pub async fn sleep(delay: i32) {
    let mut callback = |resolve: Function, _reject: Function| {
        window()
            .unwrap()
            .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, delay)
            .unwrap();
    };
    let promise = Promise::new(&mut callback);
    JsFuture::from(promise).await.unwrap();
}

/// ...
/// ...

fn use_delayed_double(x: Signal<usize>) -> Signal<usize> {
    let mut foo = use_signal(|| x());

    use_memo(move || {
        let y = x * 2;

        spawn(async move {
            log::debug!("Sleeping...");
            sleep(100).await;
            log::debug!("Writing signal");
            *foo.write() = y; // <<---- Writing to the signal.
        });
    });

    foo
}

#[allow(non_snake_case)]
fn App() -> Element {
    let mut x = use_signal(|| 123);
    let double = use_delayed_double(x);

    use_effect(move || {
        let double = double();
        log::debug!("double: {:?}", double); // <<---- Expecting the side effect to be executed.
    });

    rsx! {
        button {
            onclick: move |_| x += 1,
            "increment"
        },
        "x: {x}"
        // "double: {double}" // <<---- When commenting this line in, logging "double" works as expected.
    }
}

Launch app using dx serve.

output

[DEBUG] signal_asynchronous_write_not_rerendering - double: 123
[DEBUG] signal_asynchronous_write_not_rerendering - Sleeping...
[DEBUG] signal_asynchronous_write_not_rerendering - Writing signal

Expected behavior

output

[DEBUG] signal_asynchronous_write_not_rerendering - double: 123
[DEBUG] signal_asynchronous_write_not_rerendering - Sleeping...
[DEBUG] signal_asynchronous_write_not_rerendering - Writing signal
[DEBUG] signal_asynchronous_write_not_rerendering - double: 246 <<----

Environment:

  • Dioxus version: dioxus 0.5.4
  • Rust version: rustc 1.76.0 (07dca489a 2024-02-04)
  • OS info: macOS 14.2.1
  • 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

This seems to share the underlying issue with #2307.