From 4bfd4393dae5b1a600cfdb58ea05649ce2e30da5 Mon Sep 17 00:00:00 2001 From: Jet Li <jing.i.qin@icloud.com> Date: Tue, 5 Mar 2024 17:58:26 +0800 Subject: [PATCH] use_visible demo --- README.md | 7 +++-- crates/yew-hooks/Cargo.toml | 4 +-- crates/yew-hooks/src/hooks/use_visible.rs | 14 ++++++---- crates/yew-hooks/src/hooks/use_websocket.rs | 4 +-- examples/yew-app/src/app/home.rs | 1 + examples/yew-app/src/app/hooks/mod.rs | 2 ++ examples/yew-app/src/app/hooks/use_visible.rs | 28 +++++++++++++++++++ examples/yew-app/src/app/mod.rs | 3 ++ 8 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 examples/yew-app/src/app/hooks/use_visible.rs diff --git a/README.md b/README.md index af48b1a..da4fedf 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ fn counter() -> Html { let counter = counter.clone(); Callback::from(move |_| counter.decrease()) }; - + html! { <> <button onclick={onincrease}>{ "Increase" }</button> @@ -72,7 +72,7 @@ fn counter() -> Html { - `use_toggle` - tracks state of counterparts. - `use_bool_toggle` - tracks state of a boolean. -- `use_counter` - tracks state of a number. +- `use_counter` - tracks state of a number. - `use_latest` - returns the latest immutable ref to state or props. - `use_mut_latest` - returns the latest mutable ref to state or props. - `use_previous` - returns the previous immutable ref to state or props. @@ -134,6 +134,7 @@ fn counter() -> Html { - `use_measure` - tracks an HTML element's dimensions using the `ResizeObserver` API. - `use_geolocation` - tracks user's geographic location. - `use_swipe` - detects swipe based on TouchEvent. +- `use_visible` - checks if an element is visible. ### UI @@ -178,7 +179,7 @@ fn counter() -> Html { let counter = counter.clone(); Callback::from(move |_| counter.reset()) }; - + html! { <div> <button onclick={onincrease}>{ "Increase" }</button> diff --git a/crates/yew-hooks/Cargo.toml b/crates/yew-hooks/Cargo.toml index 27d40fa..cdde7fb 100644 --- a/crates/yew-hooks/Cargo.toml +++ b/crates/yew-hooks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yew-hooks" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Jet Li <jing.i.qin@icloud.com>"] categories = ["gui", "wasm", "web-programming"] @@ -16,7 +16,7 @@ documentation = "https://docs.rs/yew-hooks/" [dependencies] log = "0.4" -yew = { version = "0.21.0", features=["csr"] } +yew = { version = "0.21.0", features = ["csr"] } gloo = "0.10" wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" diff --git a/crates/yew-hooks/src/hooks/use_visible.rs b/crates/yew-hooks/src/hooks/use_visible.rs index 61a0d8e..812c10c 100644 --- a/crates/yew-hooks/src/hooks/use_visible.rs +++ b/crates/yew-hooks/src/hooks/use_visible.rs @@ -4,7 +4,6 @@ use yew::prelude::*; use super::use_effect_once; -#[hook] /// Check if an element is visible. Internally, it uses an [`IntersectionObserver`] to receive /// notifications from the browser whenever the visibility state of the node changes. /// @@ -15,13 +14,15 @@ use super::use_effect_once; /// # Example /// /// ```rust -/// use yew::prelude::*; -/// use yew_hooks::use_visible; +/// # use yew::prelude::*; +/// # +/// use yew_hooks::prelude::*; /// /// #[function_component] /// fn MyComponent() -> Html { /// let node = use_node_ref(); /// let visible = use_visible(node.clone(), false); +/// /// html! { /// <div ref={node}> /// if visible { @@ -33,11 +34,13 @@ use super::use_effect_once; /// } /// } /// ``` +#[hook] pub fn use_visible(node: NodeRef, sticky: bool) -> bool { // code adapted from: // https://stackoverflow.com/questions/1462138/event-listener-for-when-element-becomes-visible let visible = use_state_eq(|| false); let visible_clone = visible.clone(); + use_effect_once(move || { let closure = Closure::<dyn Fn(Vec<IntersectionObserverEntry>, IntersectionObserver)>::new( move |entries: Vec<IntersectionObserverEntry>, observer: IntersectionObserver| { @@ -45,9 +48,7 @@ pub fn use_visible(node: NodeRef, sticky: bool) -> bool { let visible = entries.iter().any(|entry| entry.intersection_ratio() > 0.0); // if the visibility changed, update the state. - if (visible != *visible_clone) && (!sticky || !*visible_clone) { - visible_clone.set(visible); - } + visible_clone.set(visible); // if this is sticky and it is currently visible, disconnect the observer. if visible && sticky { @@ -62,5 +63,6 @@ pub fn use_visible(node: NodeRef, sticky: bool) -> bool { } move || observer.disconnect() }); + *visible } diff --git a/crates/yew-hooks/src/hooks/use_websocket.rs b/crates/yew-hooks/src/hooks/use_websocket.rs index fd11804..d39a63f 100644 --- a/crates/yew-hooks/src/hooks/use_websocket.rs +++ b/crates/yew-hooks/src/hooks/use_websocket.rs @@ -33,9 +33,9 @@ pub struct UseWebSocketOptions { /// `WebSocket` close callback. pub onclose: Option<Box<dyn FnMut(CloseEvent)>>, - /// Retry times. + /// Retry times. Defaults to 3, use `u32::MAX` for infinite retries. pub reconnect_limit: Option<u32>, - /// Retry interval(ms). + /// Retry interval(ms). Defaults to 3000. pub reconnect_interval: Option<u32>, /// Manually starts connection pub manual: Option<bool>, diff --git a/examples/yew-app/src/app/home.rs b/examples/yew-app/src/app/home.rs index d968b6c..e90474f 100644 --- a/examples/yew-app/src/app/home.rs +++ b/examples/yew-app/src/app/home.rs @@ -89,6 +89,7 @@ pub fn home() -> Html { <li><Link<AppRoute> to={AppRoute::UseMeasure} classes="text-emerald-800 underline" >{ "use_measure" }</Link<AppRoute>> { " - tracks an HTML element's dimensions using the ResizeObserver API." }</li> <li><Link<AppRoute> to={AppRoute::UseGeolocation} classes="text-emerald-800 underline" >{ "use_geolocation" }</Link<AppRoute>> { " - tracks user's geographic location." }</li> <li><Link<AppRoute> to={AppRoute::UseSwipe} classes="text-emerald-800 underline" >{ "use_swipe" }</Link<AppRoute>> { " - detects swipe based on TouchEvent." }</li> + <li><Link<AppRoute> to={AppRoute::UseVisible} classes="text-emerald-800 underline" >{ "use_visible" }</Link<AppRoute>> { " - checks if an element is visible." }</li> </ul> <h2 class="text-2xl font-bold">{ "UI" }</h2> diff --git a/examples/yew-app/src/app/hooks/mod.rs b/examples/yew-app/src/app/hooks/mod.rs index 811beed..4201893 100644 --- a/examples/yew-app/src/app/hooks/mod.rs +++ b/examples/yew-app/src/app/hooks/mod.rs @@ -51,6 +51,7 @@ mod use_title; mod use_toggle; mod use_unmount; mod use_update; +mod use_visible; mod use_websocket; mod use_window_scroll; mod use_window_size; @@ -108,6 +109,7 @@ pub use use_title::*; pub use use_toggle::*; pub use use_unmount::*; pub use use_update::*; +pub use use_visible::*; pub use use_websocket::*; pub use use_window_scroll::*; pub use use_window_size::*; diff --git a/examples/yew-app/src/app/hooks/use_visible.rs b/examples/yew-app/src/app/hooks/use_visible.rs new file mode 100644 index 0000000..644b71a --- /dev/null +++ b/examples/yew-app/src/app/hooks/use_visible.rs @@ -0,0 +1,28 @@ +use yew::prelude::*; +use yew_hooks::prelude::*; + +/// `use_visible` demo +#[function_component] +pub fn UseVisible() -> Html { + let node = use_node_ref(); + let visible = use_visible(node.clone(), false); + + html! { + <div class="container"> + <header class="mt-24 text-xl text-center"> + <div class="space-x-4 space-y-4"> + <p> + <b>{ " Visible: " }</b> + { visible } + </p> + <div class="w-[600px] h-[400px] overflow-scroll bg-emerald-800 mx-auto text-slate-100"> + <div class="w-[1000px] h-[1000px] text-left"> + <div class="h-[600px]">{ "Try to scroll in this area." }</div> + <div ref={node} class="w-[100px] h-[100px] bg-slate-800"></div> + </div> + </div> + </div> + </header> + </div> + } +} diff --git a/examples/yew-app/src/app/mod.rs b/examples/yew-app/src/app/mod.rs index 8e429e5..a21f97c 100644 --- a/examples/yew-app/src/app/mod.rs +++ b/examples/yew-app/src/app/mod.rs @@ -127,6 +127,8 @@ pub enum AppRoute { UseClipboard, #[at("/use_infinite_scroll")] UseInfiniteScroll, + #[at("/use_visible")] + UseVisible, #[not_found] #[at("/page-not-found")] PageNotFound, @@ -195,6 +197,7 @@ pub fn switch(routes: AppRoute) -> Html { AppRoute::UseFavicon => html! { <UseFavicon /> }, AppRoute::UseClipboard => html! { <UseClipboard /> }, AppRoute::UseInfiniteScroll => html! { <UseInfiniteScroll /> }, + AppRoute::UseVisible => html! { <UseVisible /> }, AppRoute::PageNotFound => html! { <Home /> }, } }