Infinite scroll throttle

DEMO

The throttle strategy minimises the number of calls made within a certain time interval.

Unlike debouncing which calls the function when the event hasn't been carried out for a while, throttling calls the function while the event is being carried out.

InfiniteScroll.jsx

const throttle = (fn, delay = 500) => {
  let id;
  return function (...args) {
    if (id) return; // exit if timer exists
    fn(...args);
    id = setTimeout(() => {
      id = null; // release lock
    }, delay);
  };
};

const InfiniteScroll = () => {
  const [users, setUsers] = useState([]);

  const fetchUsers = useCallback(async () => {
    const res = await fetch(
      "https://random-data-api.com/api/users/random_user?size=50"
    );
    const data = await res.json();
    setUsers((users) => [...users, ...data]);
  }, []);

  useEffect(() => {
    fetchUsers();
  }, []);

  const ref = useRef(null);
  const hello = useCallback(
    (e) => {
      const portionScrolled =
        e.target.scrollTop / (e.target.scrollHeight - e.target.offsetHeight);
      if (portionScrolled > 0.8) {
        fetchUsers();
      }
    },
    [fetchUsers]
  );

  useEffect(() => {
    const scrollCont = ref.current;
    scrollCont.addEventListener("scroll", throttle(hello));

    return () => {
      scrollCont.removeEventListener("scroll", throttle(hello));
    };
  }, [ref, hello]);

  return (
    <Wrapper ref={ref}>
      {users.length > 0 ? (
        <UsersWrapper>
          {users.map((user, index) => (
            <User key={user.id}>
              <UserAvatar
                src={user.avatar}
                letter={user.first_name[0].toUpperCase()}
              />
              {user.first_name}
            </User>
          ))}
        </UsersWrapper>
      ) : (
        <SkeletonUsers/> 
      )}
    </Wrapper>
  );
};

Note: Code snippets do not include styling details unless they are the focus of the exercise.

Copyright © 2022 Explore React