sycamore-rs / sycamore

A library for creating reactive web apps in Rust and WebAssembly
https://sycamore-rs.netlify.app
MIT License
2.79k stars 148 forks source link

use_context Error after updating to 0.9.0-beta.2 #640

Closed jhartma closed 11 months ago

jhartma commented 11 months ago

Describe the bug After updating my working app to 0.9.0-beta.2, I get the following runtime error message in the console

sycamore-reactive-0.9.0-beta.2/src/context.rs:45:34: invalid SlotMap key used

This is what causes the error in my code:

// main component
fn main() {
    sycamore::render(|| {
        console_error_panic_hook::set_once();

        // Create a default empty app state
        let state = AppState::new();

        // Render app
        view! {
            app::App(state=state)
        }
    });
}

// Router component
#[component]
pub async fn App<G: Html>(props: AppProps) -> View<G> {
    ...
    provide_context(props.state);

    view!{ ... }
}

// This component produces the error
#[component]
pub async fn Login<G: Html>() -> View<G> {
    ...

    let login: Rc<Box<dyn Fn(String, String) -> ()>> =
        Rc::new(Box::new(move |email: String, password: String| {
            ...

            spawn_local_scoped(async move {
               ...
               let state = use_context::<AppState>();   // <-- results in error
            })
       }))

}

Environment

jhartma commented 11 months ago

The problem seems to be the Rc wrapper, once I move use_context out of it, it works

lukechu10 commented 11 months ago

Ah this might be something to do with the interaction between async components and reactive context. The error message seems to point out that there is no current_node set in Root when we are inside an async scope. I'll have to look more into this.

lukechu10 commented 11 months ago

Oh I just realised are you calling login in an event handler? If that's the case, this would be expected behaviour. Event handlers are called at the root scope where the context is not defined, thereby causing the error. The way to solve this would be to hoist the use_context out of the event handler.

jhartma commented 11 months ago

Thanks for clarifying this!

In the 0.8.2 version, I used a global state struct that had many methods that needed a handle on the state struct itself, and since context was available everywhere, I pulled in the state via use_context. But since actions where called by an event handler, I got this error all over the place when updating to 0.9.0-beta.2. Using use_context only in components and passing the state around solved it finally.