Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling suspense::use_future makes children use_effect hooks execution inconsistent. #3780

Open
1 of 3 tasks
lowlevl opened this issue Dec 17, 2024 · 2 comments
Open
1 of 3 tasks
Labels

Comments

@lowlevl
Copy link

lowlevl commented Dec 17, 2024

Problem
EDIT: This initially mentioned the leaflet library, but upon testing more, I ended up minimizing the example even further and getting rid of leaflet while still getting inconsistencies with suspense::use_future.

The use of suspense::use_future makes subsequent uses of use_effect execute before the DOM is updated, which is unexpected and inconsistent with the expected behavior.

Steps To Reproduce

  1. Use yew = { version = "0.21.0", features = ["csr"] } or yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] } and web-sys = { version = "0.3.76", features = ["HtmlElement"] }.
  2. Use this minimal example:
use yew::prelude::*;

fn main() {
    #[function_component]
    fn View() -> HtmlResult {
        // Un-commenting the following line makes the application panic on the `expect`.
        // yew::suspense::use_future(|| async {})?;

        use_effect(|| {
            web_sys::window()
                .unwrap()
                .document()
                .unwrap()
                .get_element_by_id("foo")
                .expect("Element `#foo` should be rendered when the `use_effect` hook is called.");
        });

        Ok(html! {
            <div id="foo"></div>
        })
    }

    #[function_component]
    fn App() -> Html {
        html! {<Suspense><View /></Suspense>}
    }

    yew::Renderer::<App>::new().render();
}
  1. Adding back the commented use_future call breaks the get_element_by_id call and makes the application panic.

Expected behavior
I may misunderstand the usage of use_effect, but from what I understand, it is analogous to the Component::rendered method, and I would expect the use_effect (or Component::rendered) hook to be executed after the DOM has been updated in all cases.
However when a suspension arises, the use_effect (or Component::rendered) hook seems to be executed before the updated DOM becomes available to the JS (web-sys in this case) context.

Debug tools logs

  • With the call to use_future commented: nothing (expected).
  • With the call to use_future un-commented: panics with,
panicked at src/main.rs:91:18:
Element `#foo` should be rendered when the `use_effect` hook is called.

Stack:

__wbg_get_imports/imports.wbg.__wbg_new_8a6f238a6ece86ea@http://0.0.0.0:8080/maap-66a67bc41865f4a6.js:420:21
maap-9136cacef662140e.wasm.__wbg_new_8a6f238a6ece86ea externref shim@http://0.0.0.0:8080/maap-66a67bc41865f4a6_bg.wasm:wasm-function[4516]:0x10e274
maap-9136cacef662140e.wasm.console_error_panic_hook::Error::new::hc724c5e5fa09d029@http://0.0.0.0:8080/maap-66a67bc41865f4a6_bg.wasm:wasm-function[2707]:0xf4373
maap-9136cacef662140e.wasm.console_error_panic_hook::hook_impl::h5ae464cddaa778d8@http://0.0.0.0:8080/maap-66a67bc41865f4a6_bg.wasm:wasm-function[671]:0x96e46
maap-9136cacef662140e.wasm.console_error_panic_hook::hook::h8d3226f2e8bba476@http://0.0.0.0:8080/maap-66a67bc41865f4a6_bg.wasm:wasm-function[4007]:0x10923a
maap-9136cacef662140e.wasm.core::ops::function::Fn::call::h69a48aa9a25ea0d5@http://0.0.0.0:8080/maap-66a67bc41865f4a6_bg.wasm:wasm-function[3325]:0xff9e8
m…
[maap-66a67bc41865f4a6.js:337:21](http://0.0.0.0:8080/maap-66a67bc41865f4a6.js)
Uncaught RuntimeError: unreachable executed
[maap-66a67bc41865f4a6_bg.wasm:1108023:1](http://0.0.0.0:8080/maap-66a67bc41865f4a6_bg.wasm)

Environment:

  • Yew version: 0.21.0 && master
  • Rust version: 1.83
  • Build tool: trunk
  • OS, if relevant: Ubuntu LTS (latest)
  • Browser and version, if relevant: Firefox 133.0.3 (latest at the time) && Vanadium 131.0.6778.135 (Chromium-based) on Android.

Questionnaire

  • I'm interested in fixing this myself but don't know where to start (and if it's not too much of a rabbit-hole :))
  • I would like to fix and I have a solution
  • I don't have time to fix this right now, but maybe later

Thanks for the awesome project by the way, it's a pleasure to do front-end in Rust 💯

@lowlevl lowlevl added the bug label Dec 17, 2024
@lowlevl lowlevl changed the title The suspense::use_future hook breaks leaflet maps. Calling suspense::use_future makes children use_effect hooks execution inconsistent. Dec 17, 2024
@lowlevl
Copy link
Author

lowlevl commented Dec 17, 2024

EDIT 🔝 : Minimized the example even more and got rid of the leaflet dependency.

@lowlevl
Copy link
Author

lowlevl commented Dec 17, 2024

In the meantime, I ended up not using <Suspense> elements altogether and using a combination of use_state and yew::platform::spawn_local.

    let value = use_state(|| Option::<&str>::None);

    use_effect({
        let setter = value.setter();

        || {
            yew::platform::spawn_local(async move {
                // Do async stuff.

                setter.set(Some("super value you got from async stuff"));
            })
        }
    });

    html! {
        <>
            if let Some(value) = value.as_ref() {
                {format!("The async value is {value}")}
            } else {
                {"Loading..."}
            }
        </>
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant