yew_hooks/hooks/use_infinite_scroll.rs
1use web_sys::Element;
2use yew::prelude::*;
3
4use 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::prelude::*;
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#[hook]
41pub fn use_infinite_scroll<Callback>(node: NodeRef, callback: Callback)
42where
43 Callback: Fn() + 'static,
44{
45 let callback_ref = use_latest(callback);
46 let load_more = use_state_eq(|| false);
47
48 {
49 let load_more = load_more.clone();
50 use_effect_with(load_more, move |load_more| {
51 if **load_more {
52 let callback = &*callback_ref.current();
53 callback();
54 }
55
56 || ()
57 });
58 }
59
60 let debounce = {
61 let load_more = load_more.clone();
62 use_debounce(
63 move || {
64 load_more.set(false);
65 },
66 100,
67 )
68 };
69
70 use_event(node, "scroll", move |e: Event| {
71 let element: Element = e.target_unchecked_into();
72 if element.scroll_height() - element.scroll_top() <= element.client_height() + 100 {
73 load_more.set(true);
74 debounce.run();
75 }
76 });
77}