sycamore icon indicating copy to clipboard operation
sycamore copied to clipboard

'already borrowed: BorrowMutError'

Open glademiller opened this issue 3 years ago • 3 comments
trafficstars

Describe the bug I have a view that contains an if statement that is based on a signal depending on the signals value a different subview is created. That subview has an input that is bound to a new signal created within that view. Also it creates an effect based on that new signal. When that effect is run it attempts to change the value of the outer signal which triggers the BorrowMutError. My more complex example also sometimes simply stops handling the effect after the first event but I have provided a minimal example that always appears to work as stated here.

To Reproduce

use sycamore::prelude::*;

#[component]
pub fn TestPage<G: Html>(cx: Scope<'_>) -> View<G> {
    let signal = create_signal(cx, "test".to_string());
    view! { cx,
        div {
            "TEST PAGE"
            (if *signal.get() == "test" {
                let signalt = create_signal(cx, "test2".to_string());
                create_effect(cx, || {
                    signal.set(signalt.get().to_string());
                });
                view!{cx,
                    input(bind:value=signalt)
                }
            } else {
                let signals = create_signal(cx, "test3".to_string());
                create_effect(cx, || {
                    signal.set(signals.get().to_string());
                });
                view!{cx,
                    input(bind:value=signals)

                }
            })
        }
    }
}

Expected behavior It should allow the flow above or perhaps something could be added to detect this at runtime if this isn't something that should work.

Screenshots image image

Environment

  • Sycamore: 0.8 and master
  • Browser: brave(chromium)
  • OS: Linux

Additional context Add any other context about the problem here.

glademiller avatar Oct 06 '22 14:10 glademiller

Moving the effects from inside the view macro fixes the BorrowMutError as far as I can tell. I also figured out my issue with the input losing focus in the cases when the panic doesn't happen it was being caused by the if statement being re-evaluated and the input recreated as I type. Obvious in hindsight. The following doesn't trigger the error for comparison:

use sycamore::prelude::*;

#[component]
pub fn TestPage<G: Html>(cx: Scope<'_>) -> View<G> {
    let signal = create_signal(cx, "test".to_string());
    let signalt = create_signal(cx, "test".to_string());
    let signals = create_signal(cx, "test3".to_string());
    create_effect(cx, || {
        signal.set(signalt.get().to_string());
    });
    let is_test = create_memo(cx, || signals.get().to_string() == "test");
    create_effect(cx, || {
        signal.set(signals.get().to_string());
    });
    create_effect(cx, || {
        log::info!("HELLO {}", signal.get().to_string());
    });
    view! { cx,
        div {
            "TEST PAGE"
            (if *is_test.get() {
                view!{cx, input(bind:value=signalt)}
            } else {
                view!{cx, input(bind:value=signals)}


            })
        }
    }
}

glademiller avatar Oct 06 '22 15:10 glademiller

I think I have come across the same bug. Here is an even smaller example, pressing the button instantly causes a BorrowMutError panic.

use sycamore::prelude::*;

fn main() {
    std::panic::set_hook(Box::new(console_error_panic_hook::hook));

    sycamore::futures::spawn_local(async {
        sycamore::render(|cx| {
            let a = create_signal(cx, true);

            view! {cx,
                (if *a.get() {
                    let b = create_signal(cx, ());
                    view!{cx,
                        button(on:click = move |_| {
                            a.set(false);
                            b.set(());
                        }) { "Button" }
                    }
                } else { view!{cx,} })
            }
        });
    });
}

birktj avatar Aug 13 '23 17:08 birktj

Was hoping that this would get fixed by #626 but sadly it still persists.

lukechu10 avatar Oct 06 '23 16:10 lukechu10