yew icon indicating copy to clipboard operation
yew copied to clipboard

Panic when child's view function sets parent's state

Open felixwatts opened this issue 3 years ago • 4 comments

Problem This setup causes a panic:

#[function_component(Parent)]
pub fn parent() -> Html {
    let shared_state = use_state(|| String::default());
    html{
        <Child shared_state={shared_state.clone()} />
    }
}

// snip child props

#[function_component(Child)]
pub fn child(props: &ChildProps) -> Html {
    props.shared_state.set(...);
    html!{ ... }
}

The following is printed in the JS console:

panicked at 'failed to insert tag before next sibling: JsValue(NotFoundError: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
Error: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
    at http://localhost:8000/index-c9e434318a5c50d9.js:620:35
    at handleError (http://localhost:8000/index-c9e434318a5c50d9.js:278:18)
    at imports.wbg.__wbg_insertBefore_5b314357408fbec1 (http://localhost:8000/index-c9e434318a5c50d9.js:619:75)
    at web_sys::features::gen_Node::Node::insert_before::hf68c86e22a059500 (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[10321]:0xa2d471)
    at yew::virtual_dom::insert_node::h24c5fb007c92d0d0 (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[10452]:0xa373ae)
    at yew::html::component::scope::Scope<COMP>::mount_in_place::hebcbbbc0ce7721f3 (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[1868]:0x5adfa4)
    at <yew::virtual_dom::vcomp::PropsWrapper<COMP> as yew::virtual_dom::vcomp::Mountable>::mount::h70cd3f0b7fb28805 (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[5408]:0x85bb34)
    at <yew::virtual_dom::vcomp::VComp as yew::virtual_dom::VDiff>::apply::h15ca06697f33d0e6 (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[1577]:0x553816)
    at <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::hddcbafeaa916b552 (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[600]:0x36ad9d)
    at <yew::html::component::lifecycle::RenderRunner<COMP> as yew::scheduler::Runnable>::run::h1ec6b91d9034b4be (http://localhost:8000/index-c9e434318a5c50d9_bg.wasm:wasm-function[1382]:0x50e821))', /home/felix/.cargo/registry/src/github.com-1ecc6299db9ec823/yew-0.19.3/src/virtual_dom/mod.rs:536:14

I understand this is not a good place to be setting state and I don't actually do this, but mention it anyway as it's a panic.

Environment:

  • Yew version: 0.19.3
  • Rust version: nightly
  • Target, if relevant: wasm32-unknown-unknown
  • Build tool, if relevant: trunk
  • OS, if relevant: Ubuntu
  • Browser and version, if relevant: Brave 1.37.116

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
  • [x] I don't have time to fix this right now, but maybe later

felixwatts avatar Apr 22 '22 14:04 felixwatts

~~Does work on master, so we I think we'd have to find out which patch to back-port if we want to support this.~~

EDIT: The following works also with yew 0.19.3. Can you please submit a full example without omissions, since I can't reproduce this

use yew::prelude::*;

#[function_component(Parent)]
pub fn parent() -> Html {
    let shared_state = use_state(String::default);
    html! {
        <Child {shared_state} />
    }
}

#[derive(PartialEq, Properties)]
pub struct ChildProps {
    shared_state: UseStateHandle<String>,
}

#[function_component(Child)]
pub fn child(props: &ChildProps) -> Html {
    props.shared_state.set("child rendered".to_string());
    html! { <p>{"Content"}</p> }
}

fn main() {
    yew::start_app::<Parent>();
}

WorldSEnder avatar Apr 22 '22 15:04 WorldSEnder

I am running in the same issue (yew 0.19.3). I am however not really what triggers this:

console log
14:59:38.282
panicked at 'failed to insert tag before next sibling: JsValue(NotFoundError: Node.insertBefore: Child to insert before is not a child of this node
init/imports.wbg.__wbg_insertBefore_4df558a2aa0435c1/<@https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:1009:37
handleError@https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:300:18
init/imports.wbg.__wbg_insertBefore_4df558a2aa0435c1@https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:1008:75
yew::virtual_dom::insert_node::hc98bcb53cccf2b6b@https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:wasm-function[2844]:0x2875b9
<yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7@https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:wasm-function[283]:0xd8ad6
yew::virtual_dom::vlist::VList::apply_unkeyed::h7b9dd45a5f73051b@https://…
index-1b2503aa9c5587df.js:570:21
14:59:38.283 Uncaught RuntimeError: unreachable executed
index-1b2503aa9c5587df_bg.wasm:3020460:1
    rust_panic https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:3020460
    h623ac32ff431b114 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2564502
    h4939ceabc7a11060 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2721158
    h9f6add6df687a1bf https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:3010687
    rust_begin_unwind https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:3002090
    h5118e89563022e7e https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2969850
    ha62420c192a556da https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2763334
    hc98bcb53cccf2b6b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2651679
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:887510
    h7b9dd45a5f73051b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2114283
    <yew::virtual_dom::vlist::VList as yew::virtual_dom::VDiff>::apply::h6612d2aa867ffde0 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:587337
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:888279
    h7b9dd45a5f73051b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2114283
    <yew::virtual_dom::vlist::VList as yew::virtual_dom::VDiff>::apply::h6612d2aa867ffde0 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:587337
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:888279
    <yew::html::component::lifecycle::RenderRunner<COMP> as yew::scheduler::Runnable>::run::hf92193f77819ab97 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:1564386
    h0702569f943302de https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2487935
    h5cb0843ffa0db5c4 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2491585
    h9e3f0c07ced32b82 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2985293
    hb712fa27f1a3499f https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2673324
    <yew::html::listener::events::onclick::Wrapper as yew::virtual_dom::listeners::Listener>::handle::h00b0e7d3369eb373 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:3012326
    hb7c0947cba63d3a1 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:1553730
    hc6c615f8d9ff7bec https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2511153
    <dyn core::ops::function::Fn<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hc7ade49fe9e80292 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2994115
    __wbg_adapter_58 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:295
    real https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:265
    (Async: EventListener.handleEvent)
    __wbg_addEventListener_be0c061a1359c1dd https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:890
    handleError https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:300
    __wbg_addEventListener_be0c061a1359c1dd https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:889
    h59825fc6ca316a39 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2971068
    h081b10d8d39b2b0a https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:1502243
    hb69bf4b01d097692 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:1355321
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:890592
    h7b9dd45a5f73051b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2113902
    <yew::virtual_dom::vlist::VList as yew::virtual_dom::VDiff>::apply::h6612d2aa867ffde0 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:587337
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:890825
    h7b9dd45a5f73051b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2113902
    <yew::virtual_dom::vlist::VList as yew::virtual_dom::VDiff>::apply::h6612d2aa867ffde0 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:587337
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:890825
    h7b9dd45a5f73051b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2113902
    <yew::virtual_dom::vlist::VList as yew::virtual_dom::VDiff>::apply::h6612d2aa867ffde0 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:587337
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:890825
    h7b9dd45a5f73051b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2113902
    <yew::virtual_dom::vlist::VList as yew::virtual_dom::VDiff>::apply::h6612d2aa867ffde0 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:587337
    <yew::virtual_dom::vnode::VNode as yew::virtual_dom::VDiff>::apply::h6b2d3d96d0f21ff7 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:890825
    <yew::html::component::lifecycle::RenderRunner<COMP> as yew::scheduler::Runnable>::run::h7a6f45d6033e41e1 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:833161
    h0702569f943302de https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2487935
    hd71178e89728d91d https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2655981
    h0ea7833680d41994 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2928757
    <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h7e928ef3256a2743 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2054682
    h6adae2f65af01e7e https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2264945
    <dyn core::ops::function::FnMut<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::h25183630db808d31 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2994016
    __wbg_adapter_55 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:291
    real https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:202
    (Async: promise callback)
    __wbg_then_ce526c837d07b68f https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:856
    hb48e4c009766a028 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2519219
    h2f0a3d325e57256e https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2858905
    h335cd0490da6cfe2 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2861577
    <wasm_bindgen_futures::JsFuture as core::convert::From<js_sys::Promise>>::from::finish::hc421782b42cf9828 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2570844
    <T as wasm_bindgen::closure::WasmClosureFnOnce<A,R>>::into_fn_mut::{{closure}}::h20805aaaa86cd129 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2897841
    <dyn core::ops::function::FnMut<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::h25183630db808d31 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2994016
    __wbg_adapter_55 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:291
    real https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:202
    (Async: promise callback)
    __wbg_then_842e65b843962f56 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:852
    <wasm_bindgen_futures::JsFuture as core::convert::From<js_sys::Promise>>::from::h71cef0d09f71b62b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2456726
    <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::hb3e695b88e0fb507 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2163820
    <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h5ea5cbda1d07045e https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:1031371
    <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h8a8fa2d46c140836 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:111433
    <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h7e928ef3256a2743 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2054470
    h6adae2f65af01e7e https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2264945
    <dyn core::ops::function::FnMut<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::h25183630db808d31 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2994016
    __wbg_adapter_55 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:291
    real https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:202
    (Async: promise callback)
    __wbg_then_ce526c837d07b68f https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:856
    hb48e4c009766a028 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2519219
    h2f0a3d325e57256e https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2858905
    h335cd0490da6cfe2 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2861577
    <wasm_bindgen_futures::JsFuture as core::convert::From<js_sys::Promise>>::from::finish::hc421782b42cf9828 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2570844
    <T as wasm_bindgen::closure::WasmClosureFnOnce<A,R>>::into_fn_mut::{{closure}}::h20805aaaa86cd129 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2897841
    <dyn core::ops::function::FnMut<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::h25183630db808d31 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2994016
    __wbg_adapter_55 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:291
    real https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:202
    (Async: promise callback)
    __wbg_then_842e65b843962f56 https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df.js:852
    <wasm_bindgen_futures::JsFuture as core::convert::From<js_sys::Promise>>::from::h71cef0d09f71b62b https://console-drogue-dev.apps.wonderful.iot-playground.org/index-1b2503aa9c5587df_bg.wasm:2456726

ctron avatar Jun 20 '22 13:06 ctron

I just got the same panic and managed to produce a minimal example:

use yew::prelude::*;
fn main() {
    yew::start_app::<Model>();
}

#[function_component(Model)]
fn test() -> html {
    let state = use_state(|| (true, false));

    let cb = {
        let state = state.clone();
        Callback::from(move |_| {
            state.set((false, true));
        })
    };

    html! {
        <div>
            <button onclick={cb}>{"Click me"}</button>
            <Text display={state.0}/>
            <Text display={state.1}/>
        </div>
    }
}

#[derive(Properties, PartialEq)]
struct Props {
    display: bool,
}

#[function_component(Text)]
fn text(props: &Props) -> html {
    if props.display {
        html! { <p> {"Hello"} </p> }
    } else {
        html! {}
    }
}

Pressing "click me" triggers the panic. As I understand it, the problem seems to be removing and adding a child element at the same time. Yew tries to add the new child after the previous child, but the previous child doesn't exist anymore.

ma1ko avatar Sep 14 '22 10:09 ma1ko

Just found #2859. So can probably be closed in favor for the other one, which describes workarounds.

ma1ko avatar Sep 14 '22 10:09 ma1ko