Skip to content

Commit

Permalink
add use_infinite_scroll (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
jetli authored May 7, 2022
1 parent 9c964d5 commit 7ccfe08
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 15 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ fn counter() -> Html {
- `use_window_scroll` - tracks Window scroll position.
- `use_scroll` - tracks an HTML element's scroll position.
- `use_scrolling` - tracks whether HTML element is scrolling.
- `use_infinite_scroll` - infinite scrolling of the element.
- `use_location` - tracks brower's location value.
- `use_hash` - tracks brower's location hash value.
- `use_search_param` - tracks brower's location search param value.
Expand Down
2 changes: 1 addition & 1 deletion crates/yew-hooks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "yew-hooks"
version = "0.1.54"
version = "0.1.55"
edition = "2018"
authors = ["Jet Li <jing.i.qin@icloud.com>"]
categories = ["gui", "wasm", "web-programming"]
Expand Down
2 changes: 2 additions & 0 deletions crates/yew-hooks/src/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod use_event;
mod use_favicon;
mod use_geolocation;
mod use_hash;
mod use_infinite_scroll;
mod use_interval;
mod use_is_first_mount;
mod use_is_mounted;
Expand Down Expand Up @@ -69,6 +70,7 @@ pub use use_event::*;
pub use use_favicon::*;
pub use use_geolocation::*;
pub use use_hash::*;
pub use use_infinite_scroll::*;
pub use use_interval::*;
pub use use_is_first_mount::*;
pub use use_is_mounted::*;
Expand Down
79 changes: 79 additions & 0 deletions crates/yew-hooks/src/hooks/use_infinite_scroll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use web_sys::Element;
use yew::prelude::*;

use super::{use_debounce, use_event, use_latest};

/// A sensor hook that tracks infinite scrolling of the element.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// #
/// use yew_hooks::{use_infinite_scroll, use_list};
///
/// #[function_component(UseInfiniteScroll)]
/// fn infinite_scroll() -> Html {
/// let node = use_node_ref();
/// let state = use_list(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
///
/// {
/// let state = state.clone();
/// use_infinite_scroll(node.clone(), move || {
/// let max = state.current().len() + 1;
/// let mut more = vec![max, max + 1, max + 2, max + 3, max + 4];
/// state.append(&mut more);
/// });
/// }
///
/// html! {
/// <div ref={node}>
/// {
/// for state.current().iter().map(|element| {
/// html! { <p>{ element }</p> }
/// })
/// }
/// </div>
/// }
/// }
/// ```
pub fn use_infinite_scroll<Callback>(node: NodeRef, callback: Callback)
where
Callback: Fn() + 'static,
{
let callback_ref = use_latest(callback);
let load_more = use_state_eq(|| false);

{
let load_more = load_more.clone();
use_effect_with_deps(
move |load_more| {
if **load_more {
let callback = &*callback_ref.current();
callback();
}

|| ()
},
load_more,
);
}

let debounce = {
let load_more = load_more.clone();
use_debounce(
move || {
load_more.set(false);
},
150,
)
};

use_event(node, "scroll", move |e: Event| {
let element: Element = e.target_unchecked_into();
if element.scroll_height() - element.scroll_top() <= element.client_height() {
load_more.set(true);
debounce.run();
}
});
}
26 changes: 13 additions & 13 deletions crates/yew-hooks/src/hooks/use_scrolling.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use gloo::timers::callback::Timeout;
use yew::prelude::*;

use super::{use_event, use_unmount};
use super::{use_debounce, use_event};

/// A sensor hook that tracks whether HTML element is scrolling.
///
Expand All @@ -26,24 +25,25 @@ use super::{use_event, use_unmount};
/// }
/// ```
pub fn use_scrolling(node: NodeRef) -> bool {
let state = use_state(|| false);
let timer = use_mut_ref(|| None);
let state = use_state_eq(|| false);

let debounce = {
let state = state.clone();
use_debounce(
move || {
state.set(false);
},
150,
)
};

{
let state = state.clone();
let timer = timer.clone();
use_event(node, "scroll", move |_: Event| {
state.set(true);
let state = state.clone();
*timer.borrow_mut() = Some(Timeout::new(150, move || {
state.set(false);
}));
debounce.run();
});
}

use_unmount(move || {
*timer.borrow_mut() = None;
});

*state
}
3 changes: 2 additions & 1 deletion examples/yew-app/src/routes/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn home() -> Html {
<li><Link<AppRoute> to={AppRoute::UseSet} classes="app-link">{ "use_set" }</Link<AppRoute>> { " - tracks state of a hash set." }</li>
<li><Link<AppRoute> to={AppRoute::UseQueue} classes="app-link">{ "use_queue" }</Link<AppRoute>> { " - tracks state of a queue." }</li>
<li><Link<AppRoute> to={AppRoute::UseRafState} classes="app-link">{ "use_raf_state" }</Link<AppRoute>> { " - creates set method which only updates after requestAnimationFrame." }</li>
<li><Link<AppRoute> to={AppRoute::UseStatePtrEq} classes="app-link">{ "use_state_ptr_eq" }</Link<AppRoute>> { " - similar to use_state_eq, but checks if the two Rcs of values point to the same allocation." }</li>
<li><Link<AppRoute> to={AppRoute::UseStatePtrEq} classes="app-link">{ "use_state_ptr_eq" }</Link<AppRoute>> { " - similar to use_state_eq, but checks two Rcs' pointers of allocation." }</li>
<li><Link<AppRoute> to={AppRoute::UseRendersCount} classes="app-link">{ "use_renders_count" }</Link<AppRoute>> { " - counts component renders." }</li>
<li><Link<AppRoute> to={AppRoute::UseDefault} classes="app-link">{ "use_default" }</Link<AppRoute>> { " - returns the default value when state is None." }</li>
<li><Link<AppRoute> to={AppRoute::UseDebounceState} classes="app-link">{ "use_debounce_state" }</Link<AppRoute>> { " - debounces state." }</li>
Expand Down Expand Up @@ -78,6 +78,7 @@ pub fn home() -> Html {
<li><Link<AppRoute> to={AppRoute::UseWindowScroll} classes="app-link" >{ "use_window_scroll" }</Link<AppRoute>> { " - tracks Window scroll position." }</li>
<li><Link<AppRoute> to={AppRoute::UseScroll} classes="app-link" >{ "use_scroll" }</Link<AppRoute>> { " - tracks an HTML element's scroll position." }</li>
<li><Link<AppRoute> to={AppRoute::UseScrolling} classes="app-link" >{ "use_scrolling" }</Link<AppRoute>> { " - tracks whether HTML element is scrolling." }</li>
<li><Link<AppRoute> to={AppRoute::UseInfiniteScroll} classes="app-link" >{ "use_infinite_scroll" }</Link<AppRoute>> { " - infinite scrolling of the element." }</li>
<li><Link<AppRoute> to={AppRoute::UseLocation} classes="app-link" >{ "use_location" }</Link<AppRoute>> { " - tracks brower's location value." }</li>
<li><Link<AppRoute> to={AppRoute::UseHash} classes="app-link" >{ "use_hash" }</Link<AppRoute>> { " - tracks brower's location hash value." }</li>
<li><Link<AppRoute> to={AppRoute::UseSearchParam} classes="app-link" >{ "use_search_param" }</Link<AppRoute>> { " - tracks brower's location search param value." }</li>
Expand Down
2 changes: 2 additions & 0 deletions examples/yew-app/src/routes/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod use_event;
mod use_favicon;
mod use_geolocation;
mod use_hash;
mod use_infinite_scroll;
mod use_interval;
mod use_is_first_mount;
mod use_is_mounted;
Expand Down Expand Up @@ -72,6 +73,7 @@ pub use use_event::*;
pub use use_favicon::*;
pub use use_geolocation::*;
pub use use_hash::*;
pub use use_infinite_scroll::*;
pub use use_interval::*;
pub use use_is_first_mount::*;
pub use use_is_mounted::*;
Expand Down
39 changes: 39 additions & 0 deletions examples/yew-app/src/routes/hooks/use_infinite_scroll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use yew::prelude::*;

use yew_hooks::{use_infinite_scroll, use_list};

/// `use_infinite_scroll` demo
#[function_component(UseInfiniteScroll)]
pub fn infinite_scroll() -> Html {
let node = use_node_ref();
let state = use_list(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

{
let state = state.clone();
use_infinite_scroll(node.clone(), move || {
let max = state.current().len() + 1;
let mut more = vec![max, max + 1, max + 2, max + 3, max + 4];
state.append(&mut more);
});
}

html! {
<div class="app">
<header class="app-header">
<div>
<div ref={node} style="width: 600px; height:300px; overflow: scroll; background-color: #61dafb;">
<div>
{ "Try to scroll in this area vertically." }
{
for state.current().iter().map(|element| {
html! { <p style="height: 50px;">{ element }</p> }
})
}

</div>
</div>
</div>
</header>
</div>
}
}
3 changes: 3 additions & 0 deletions examples/yew-app/src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub enum AppRoute {
UseFavicon,
#[at("/use_clipboard")]
UseClipboard,
#[at("/use_infinite_scroll")]
UseInfiniteScroll,
#[not_found]
#[at("/page-not-found")]
PageNotFound,
Expand Down Expand Up @@ -191,6 +193,7 @@ pub fn switch(routes: &AppRoute) -> Html {
AppRoute::UseThrottleEffect => html! { <UseThrottleEffect /> },
AppRoute::UseFavicon => html! { <UseFavicon /> },
AppRoute::UseClipboard => html! { <UseClipboard /> },
AppRoute::UseInfiniteScroll => html! { <UseInfiniteScroll /> },
AppRoute::PageNotFound => html! { <Home /> },
}
}

0 comments on commit 7ccfe08

Please sign in to comment.