-
I'm mounting a view inside content not controlled by leptos, but I can't find a way to dismount that content when needed. [package]
name = "leptos-mount"
version = "0.1.0"
edition = "2021"
[dependencies]
leptos = { version = "0.4.2", features = ["csr"] }
wasm-bindgen = "0.2.87"
web-sys = { version = "0.3.64", features = ["HtmlElement"]} <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Leptos-Mount</title>
</head>
<body>
<div id="target" style="border: dashed 1px blue; margin: 10px;">
<b>mount-target</b>
</div>
</body>
</html> use leptos::*;
use wasm_bindgen::JsCast;
use web_sys::HtmlElement;
fn main() {
mount_to_body(|cx| view! {cx, <App/> } );
}
#[component]
pub fn App(cx: Scope) -> impl IntoView {
let (count, set_count) = create_signal(cx, 0);
let increment_count = move |_| { set_count.update(|count| *count += 1); };
let remove_target = move |_| {
// of course, removing the target node won't drop the live mounted view instance
// let target_element = window().document().unwrap().query_selector("#target")
// .unwrap()
// .unwrap()
// ;
// target_element.remove();
};
// this time, that target element is from hard-coded content in index.html
let target_element = window().document().unwrap().query_selector("#target")
.unwrap() // The query is fixed and valid
.unwrap() // I'm really sure that the target exists
.unchecked_into::<HtmlElement>(); // downcast from Element to HtmlElement
// mount in #target, but no access to a handle!
leptos::mount_to(target_element, move |cx| {
view! {cx,
<div style="border: dashed 1px red; margin: 10px;">
<b>"mounted in #target"</b>
// this custom component will stop logging changes in count after this view get dismounted
<CustomComponent count=count />
</div>
}
});
view! {cx,
<button on:click=increment_count>Next Count</button>
<button on:click=remove_target>Remove Target</button>
}
}
#[component]
pub fn CustomComponent(
cx: Scope,
count: ReadSignal<i32>,
) -> impl IntoView {
create_effect(cx, move |_| {
log!("count: {}", count.get()); // the custom component will stop logging changes in count after it get dismounted
});
view! {cx,
<div style="border: dashed 1px black; margin: 10px;">
<b>custom component</b>
<div>count: {move || count.get()}</div>
</div>
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 3 replies
-
Here's what I'd do! #[component]
pub fn App(cx: Scope) -> impl IntoView {
// determines whether the component is in the DOM or not
let (visible, set_visible) = create_signal(cx, true);
// ...
// remove_target just toggles that signal
let remove_target = move |_| {
set_visible.set(false);
};
// ...
// mount in #target, but no access to a handle!
leptos::mount_to(target_element, move |cx| {
view! {cx,
<div
node_ref=unmount_handle
style="border: dashed 1px red; margin: 10px;"
>
<b>"mounted in #target"</b>
// wrap it in <Show/>
<Show when=move || visible.get()
fallback=|_| ()
>
// this custom component will stop logging changes in count after this view get dismounted
<CustomComponent count=count />
</Show>
</div>
}
});
// ... |
Beta Was this translation helpful? Give feedback.
-
Thank you very much, your answer is already covering fixed targets as was the case with the sample I provided, Unfortunately, It falls short for non-fixed targets as was the case when trying to render live leptos views in dom targets created by leaflet.
svelte required a portal and the solution was like the following, not sure if I need to create a custom portal component (if it really works)?: <script>
// some content...
marker.addEventListener('add', () => {
marker_attached = true
})
marker.addEventListener('remove', () => {
marker_attached = false
})
</script>
{#if marker_attached}
<div use:portal={`.custom-marker-type.${unique-marker-class}`} hidden>
<svg>
<!-- custom live content -->
</svg>
</div>
{/if} Edit: Questions:
|
Beta Was this translation helpful? Give feedback.
-
May this will help with the creation of a custom portal component (I'll try later).
Question: How to kill a view mounted with |
Beta Was this translation helpful? Give feedback.
-
@gbj, I really appreciate your non trivial efforts after seeing many github projects not providing the discussions tab at all. I suppose that nearly all my questions are clear enough (but not claiming all of them are simplified enough). unfortunately, I'm not receiving answers to some clear questions as is the case with (e.g: How to kill a view mounted with leptos::mount_to?).
I should've said "reactive view" instead. Let's no drag this discussion any longer, and better to discuss different matters in more specialized topics whenever needed. I'll try to build a custom portal component based on some of your suggestions in this discussion and try to report later about success if any. Conclusion:
Thank you very much. |
Beta Was this translation helpful? Give feedback.
-
I suppose that the word "kill" is quite popular for getting rid of everything related. to kill a gui process in linux, you'll kill the process, children processes, and nothing will be left on screen. By killing a leptos view, you'll remove content from dom, and dispose of reactive context as stated by your last post. Thank you very much, your last post is providing matching answers to my questions. Best Regards |
Beta Was this translation helpful? Give feedback.
-
For those interested I've found the use leptos::*;
pub fn mount_with_unmount<F, N>(f: F) -> Mount
where
F: FnOnce(Scope) -> N + 'static,
N: IntoView,
{
leptos::mount_to_body(f);
Mount
}
pub struct Mount;
impl Drop for Mount {
fn drop(&mut self) { clear_body() }
}
fn clear_body() {
let window = window().unwrap();
let body = window.document().unwrap().body().unwrap();
while let Some(child) = body.first_child() {
body.remove_child(&child).unwrap();
}
} |
Beta Was this translation helpful? Give feedback.
Fair enough. I still don't understand what "kill a view" here means, I'm afraid. Sorry for the miscommunication here--it definitely seems like that's a clear question to you and not to me.
One final word, if it's helpful in your life exploration:
mount_to
just gives you aScope
in the reactive system and expects you to return aView
.View
is just an enum that wraps a couple different types of, basically, smart pointers to DOM nodes.I can imagine "kill" meaning
These would be achieved by
Element::remove()
Scope::dispose()
So if you
…