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}