npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

use-simple-infinite-scroll

v1.1.0

Published

A simple React Hook for infinite scrolling built on the Intersection Observer API

Downloads

21

Readme

License Actions Status NPM Version Downloads Month Downloads Total Dependencies Status Semantic Release Commitizen Friendly PRs Welcome

All Contributors

Installation

npm install use-simple-infinite-scroll

Usage

Edit kotarella1110/use-simple-infinite-scroll: example

Basic

import React, { useState } from 'react';
import { useSimpleInfiniteScroll } from 'use-simple-infinite-scroll';

type Item = {
  id: number;
  name: string;
};

type Result = {
  data: Item[];
  nextCursor: number | null;
};

const canFetchMore = (nextCursor: Result['nextCursor']) => nextCursor !== null;

const InfiniteScrollExample = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [items, setItems] = useState<Item[]>([]);
  const [nextCursor, setNextCursor] = useState<Result['nextCursor']>(0);

  const fetchMore = () => {
    setIsLoading(true);
    fetch(`/api/items?cursor=${nextCursor}`)
      .then((res) => res.json())
      .then((res: Result) => {
        setItems([...items, ...res.data]);
        setNextCursor(res.nextCursor);
        setIsLoading(false);
      });
  };

  const [targetRef] = useSimpleInfiniteScroll({
    onLoadMore: fetchMore,
    canLoadMore: canFetchMore(nextCursor),
  });

  return (
    <>
      {items.length !== 0 ? (
        <ul>
          {items.map((item) => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
      ) : null}
      <div ref={targetRef}>
        {isLoading
          ? 'Loading more...'
          : canFetchMore(nextCursor)
          ? 'Load More'
          : 'Nothing more to load'}
      </div>
    </>
  );
};

React Query

import React from 'react';
import { useInfiniteQuery } from 'react-query';
import { useSimpleInfiniteScroll } from 'use-simple-infinite-scroll';

type Item = {
  id: number;
  name: string;
};

type Result = {
  data: Item[];
  nextCursor: number | null;
};

const InfiniteScrollExample = () => {
  const {
    status,
    data,
    error,
    isFetching,
    isFetchingMore,
    fetchMore,
    canFetchMore,
  } = useInfiniteQuery<Result, Error>(
    'items',
    (key: string, cursor = 0) =>
      fetch(`/api/items?cursor=${cursor}`).then((res) => res.json()),
    {
      getFetchMore: (lastGroup) => lastGroup.nextCursor,
    },
  );

  const [targetRef, rootRef] = useSimpleInfiniteScroll({
    onLoadMore: fetchMore,
    canLoadMore: !!canFetchMore,
  });

  return status === 'loading' ? (
    <p>Loading...</p>
  ) : status === 'error' ? (
    <span>Error: {error && error.message}</span>
  ) : (
    <div
      style={{
        overflow: 'auto',
      }}
      ref={rootRef}
    >
      <ul>
        {data &&
          data.map((page, i) => (
            <React.Fragment key={i}>
              {page.data.map((item) => (
                <li key={itme.id}>{item.name}</li>
              ))}
            </React.Fragment>
          ))}
      </ul>
      <div>
        <button
          type="button"
          ref={targetRef}
          onClick={() => fetchMore()}
          disabled={!canFetchMore || !!isFetchingMore}
        >
          {isFetchingMore
            ? 'Loading more...'
            : canFetchMore
            ? 'Load More'
            : 'Nothing more to load'}
        </button>
      </div>
      <div>
        {isFetching && !isFetchingMore ? 'Background Updating...' : null}
      </div>
    </div>
  );
};

API

const useSimpleInfiniteScroll: (options: {
  canLoadMore: boolean;
  onLoadMore: () => void;
  rootMargin?: string;
  threshold?: number | number[];
}) => [(target: Element | null) => void, (root: Element | null) => void];

| Name | Type | Default | Required | Descripttion | | :------------ | :------------------- | :------ | :------: | :----------------------------------------------------------------------------------------------------------------------------------------------------- | | canLoadMore | boolean | | ✓ | Specifies if there are more entities to load. | | onLoadMore | () => void | | ✓ | Called when the user has scrolled all the way to the end. | | rootMargin | string | "0px" | | Margin around the root. Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left). | | threshold | number \| number[] | 0 | | Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed. |

For more information on rootMargin and threshold option, visit the MDN web docs.

FAQ

How can I assign multiple refs to a component?

You can wrap multiple ref assignments in a single useCallback:

import React, { useRef, useCallback } from 'react';
import { useSimpleInfiniteScroll } from 'use-simple-infinite-scroll';

const AssignMultipleRefsExample = () => {
  const rootRef = useRef<HTMLDivElement | null>();
  const targetRef = useRef<HTMLDivElement | null>();

  const [setTargetRef, setRootRef] = useSimpleInfiniteScroll({
    onLoadMore: () => {},
    canLoadMore: true,
  });

  // Use `useCallback` so we don't recreate the function on each render - Otherwise, the function passed to `onLoadMore` option will be called twice
  const setRootRefs = useCallback(
    (node: HTMLDivElement | null) => {
      // Ref's from useRef needs to have the node assigned to `current`
      rootRef.current = node;
      // Callback refs, like the one from `useSimpleInfiniteScroll`, is a function that takes the node as an argument
      setRootRef(node);
    },
    [setRootRef],
  );

  const setTargetRefs = useCallback(
    (node: HTMLDivElement | null) => {
      targetRef.current = node;
      setTargetRef(node);
    },
    [setTargetRef],
  );

  return (
    <div ref={setRootRefs}>
      <div ref={setTargetRefs} />
    </div>
  );
};

Which browsers are supported?

use-simple-infinite-scroll supports all of the major modern browsers. Browsers like IE11 are not supported: if you need to support older browsers you can add IntersectionObserver polyfill.

You can install the polyfill via npm or by downloading a zip of this repository:

npm install intersection-observer

Then import it in your app:

import 'intersection-observer';

Contributing

Contributions are always welcome! Please read the contributing first.

Contributors

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!

License

MIT © Kotaro Sugawara