Skip to content

Commit 7ccfe08

Browse files
authored
add use_infinite_scroll (#12)
1 parent 9c964d5 commit 7ccfe08

File tree

9 files changed

+142
-15
lines changed

9 files changed

+142
-15
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ fn counter() -> Html {
126126
- `use_window_scroll` - tracks Window scroll position.
127127
- `use_scroll` - tracks an HTML element's scroll position.
128128
- `use_scrolling` - tracks whether HTML element is scrolling.
129+
- `use_infinite_scroll` - infinite scrolling of the element.
129130
- `use_location` - tracks brower's location value.
130131
- `use_hash` - tracks brower's location hash value.
131132
- `use_search_param` - tracks brower's location search param value.

crates/yew-hooks/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "yew-hooks"
3-
version = "0.1.54"
3+
version = "0.1.55"
44
edition = "2018"
55
authors = ["Jet Li <[email protected]>"]
66
categories = ["gui", "wasm", "web-programming"]

crates/yew-hooks/src/hooks/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod use_event;
1515
mod use_favicon;
1616
mod use_geolocation;
1717
mod use_hash;
18+
mod use_infinite_scroll;
1819
mod use_interval;
1920
mod use_is_first_mount;
2021
mod use_is_mounted;
@@ -69,6 +70,7 @@ pub use use_event::*;
6970
pub use use_favicon::*;
7071
pub use use_geolocation::*;
7172
pub use use_hash::*;
73+
pub use use_infinite_scroll::*;
7274
pub use use_interval::*;
7375
pub use use_is_first_mount::*;
7476
pub use use_is_mounted::*;
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use web_sys::Element;
2+
use yew::prelude::*;
3+
4+
use super::{use_debounce, use_event, use_latest};
5+
6+
/// A sensor hook that tracks infinite scrolling of the element.
7+
///
8+
/// # Example
9+
///
10+
/// ```rust
11+
/// # use yew::prelude::*;
12+
/// #
13+
/// use yew_hooks::{use_infinite_scroll, use_list};
14+
///
15+
/// #[function_component(UseInfiniteScroll)]
16+
/// fn infinite_scroll() -> Html {
17+
/// let node = use_node_ref();
18+
/// let state = use_list(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
19+
///
20+
/// {
21+
/// let state = state.clone();
22+
/// use_infinite_scroll(node.clone(), move || {
23+
/// let max = state.current().len() + 1;
24+
/// let mut more = vec![max, max + 1, max + 2, max + 3, max + 4];
25+
/// state.append(&mut more);
26+
/// });
27+
/// }
28+
///
29+
/// html! {
30+
/// <div ref={node}>
31+
/// {
32+
/// for state.current().iter().map(|element| {
33+
/// html! { <p>{ element }</p> }
34+
/// })
35+
/// }
36+
/// </div>
37+
/// }
38+
/// }
39+
/// ```
40+
pub fn use_infinite_scroll<Callback>(node: NodeRef, callback: Callback)
41+
where
42+
Callback: Fn() + 'static,
43+
{
44+
let callback_ref = use_latest(callback);
45+
let load_more = use_state_eq(|| false);
46+
47+
{
48+
let load_more = load_more.clone();
49+
use_effect_with_deps(
50+
move |load_more| {
51+
if **load_more {
52+
let callback = &*callback_ref.current();
53+
callback();
54+
}
55+
56+
|| ()
57+
},
58+
load_more,
59+
);
60+
}
61+
62+
let debounce = {
63+
let load_more = load_more.clone();
64+
use_debounce(
65+
move || {
66+
load_more.set(false);
67+
},
68+
150,
69+
)
70+
};
71+
72+
use_event(node, "scroll", move |e: Event| {
73+
let element: Element = e.target_unchecked_into();
74+
if element.scroll_height() - element.scroll_top() <= element.client_height() {
75+
load_more.set(true);
76+
debounce.run();
77+
}
78+
});
79+
}

crates/yew-hooks/src/hooks/use_scrolling.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use gloo::timers::callback::Timeout;
21
use yew::prelude::*;
32

4-
use super::{use_event, use_unmount};
3+
use super::{use_debounce, use_event};
54

65
/// A sensor hook that tracks whether HTML element is scrolling.
76
///
@@ -26,24 +25,25 @@ use super::{use_event, use_unmount};
2625
/// }
2726
/// ```
2827
pub fn use_scrolling(node: NodeRef) -> bool {
29-
let state = use_state(|| false);
30-
let timer = use_mut_ref(|| None);
28+
let state = use_state_eq(|| false);
29+
30+
let debounce = {
31+
let state = state.clone();
32+
use_debounce(
33+
move || {
34+
state.set(false);
35+
},
36+
150,
37+
)
38+
};
3139

3240
{
3341
let state = state.clone();
34-
let timer = timer.clone();
3542
use_event(node, "scroll", move |_: Event| {
3643
state.set(true);
37-
let state = state.clone();
38-
*timer.borrow_mut() = Some(Timeout::new(150, move || {
39-
state.set(false);
40-
}));
44+
debounce.run();
4145
});
4246
}
4347

44-
use_unmount(move || {
45-
*timer.borrow_mut() = None;
46-
});
47-
4848
*state
4949
}

examples/yew-app/src/routes/home.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn home() -> Html {
2525
<li><Link<AppRoute> to={AppRoute::UseSet} classes="app-link">{ "use_set" }</Link<AppRoute>> { " - tracks state of a hash set." }</li>
2626
<li><Link<AppRoute> to={AppRoute::UseQueue} classes="app-link">{ "use_queue" }</Link<AppRoute>> { " - tracks state of a queue." }</li>
2727
<li><Link<AppRoute> to={AppRoute::UseRafState} classes="app-link">{ "use_raf_state" }</Link<AppRoute>> { " - creates set method which only updates after requestAnimationFrame." }</li>
28-
<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>
28+
<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>
2929
<li><Link<AppRoute> to={AppRoute::UseRendersCount} classes="app-link">{ "use_renders_count" }</Link<AppRoute>> { " - counts component renders." }</li>
3030
<li><Link<AppRoute> to={AppRoute::UseDefault} classes="app-link">{ "use_default" }</Link<AppRoute>> { " - returns the default value when state is None." }</li>
3131
<li><Link<AppRoute> to={AppRoute::UseDebounceState} classes="app-link">{ "use_debounce_state" }</Link<AppRoute>> { " - debounces state." }</li>
@@ -78,6 +78,7 @@ pub fn home() -> Html {
7878
<li><Link<AppRoute> to={AppRoute::UseWindowScroll} classes="app-link" >{ "use_window_scroll" }</Link<AppRoute>> { " - tracks Window scroll position." }</li>
7979
<li><Link<AppRoute> to={AppRoute::UseScroll} classes="app-link" >{ "use_scroll" }</Link<AppRoute>> { " - tracks an HTML element's scroll position." }</li>
8080
<li><Link<AppRoute> to={AppRoute::UseScrolling} classes="app-link" >{ "use_scrolling" }</Link<AppRoute>> { " - tracks whether HTML element is scrolling." }</li>
81+
<li><Link<AppRoute> to={AppRoute::UseInfiniteScroll} classes="app-link" >{ "use_infinite_scroll" }</Link<AppRoute>> { " - infinite scrolling of the element." }</li>
8182
<li><Link<AppRoute> to={AppRoute::UseLocation} classes="app-link" >{ "use_location" }</Link<AppRoute>> { " - tracks brower's location value." }</li>
8283
<li><Link<AppRoute> to={AppRoute::UseHash} classes="app-link" >{ "use_hash" }</Link<AppRoute>> { " - tracks brower's location hash value." }</li>
8384
<li><Link<AppRoute> to={AppRoute::UseSearchParam} classes="app-link" >{ "use_search_param" }</Link<AppRoute>> { " - tracks brower's location search param value." }</li>

examples/yew-app/src/routes/hooks/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod use_event;
1616
mod use_favicon;
1717
mod use_geolocation;
1818
mod use_hash;
19+
mod use_infinite_scroll;
1920
mod use_interval;
2021
mod use_is_first_mount;
2122
mod use_is_mounted;
@@ -72,6 +73,7 @@ pub use use_event::*;
7273
pub use use_favicon::*;
7374
pub use use_geolocation::*;
7475
pub use use_hash::*;
76+
pub use use_infinite_scroll::*;
7577
pub use use_interval::*;
7678
pub use use_is_first_mount::*;
7779
pub use use_is_mounted::*;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use yew::prelude::*;
2+
3+
use yew_hooks::{use_infinite_scroll, use_list};
4+
5+
/// `use_infinite_scroll` demo
6+
#[function_component(UseInfiniteScroll)]
7+
pub fn infinite_scroll() -> Html {
8+
let node = use_node_ref();
9+
let state = use_list(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
10+
11+
{
12+
let state = state.clone();
13+
use_infinite_scroll(node.clone(), move || {
14+
let max = state.current().len() + 1;
15+
let mut more = vec![max, max + 1, max + 2, max + 3, max + 4];
16+
state.append(&mut more);
17+
});
18+
}
19+
20+
html! {
21+
<div class="app">
22+
<header class="app-header">
23+
<div>
24+
<div ref={node} style="width: 600px; height:300px; overflow: scroll; background-color: #61dafb;">
25+
<div>
26+
{ "Try to scroll in this area vertically." }
27+
{
28+
for state.current().iter().map(|element| {
29+
html! { <p style="height: 50px;">{ element }</p> }
30+
})
31+
}
32+
33+
</div>
34+
</div>
35+
</div>
36+
</header>
37+
</div>
38+
}
39+
}

examples/yew-app/src/routes/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ pub enum AppRoute {
124124
UseFavicon,
125125
#[at("/use_clipboard")]
126126
UseClipboard,
127+
#[at("/use_infinite_scroll")]
128+
UseInfiniteScroll,
127129
#[not_found]
128130
#[at("/page-not-found")]
129131
PageNotFound,
@@ -191,6 +193,7 @@ pub fn switch(routes: &AppRoute) -> Html {
191193
AppRoute::UseThrottleEffect => html! { <UseThrottleEffect /> },
192194
AppRoute::UseFavicon => html! { <UseFavicon /> },
193195
AppRoute::UseClipboard => html! { <UseClipboard /> },
196+
AppRoute::UseInfiniteScroll => html! { <UseInfiniteScroll /> },
194197
AppRoute::PageNotFound => html! { <Home /> },
195198
}
196199
}

0 commit comments

Comments
 (0)