5

Simplify Infinite Loading with React Query

 1 year ago
source link: https://dev.to/brainiacneit/simplify-infinite-loading-with-react-query-48oj
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Introduction

Fetching data in React applications can be a challenge, especially when it comes to infinite loading. React provides no built-in way to handle infinite loading, and it can be difficult to manage the state of data as it's being fetched.

Infinite loading is a common problem in web applications that display large amounts of data, such as social media feeds or product listings. Users expect these types of applications to load quickly and smoothly, even as more data is loaded.

Fortunately, there's a powerful library that can help simplify infinite loading in React applications: React Query. React Query provides a simple and efficient way to manage data fetching and caching in React applications, making it easier to handle infinite loading and improve the overall performance of your application.

Set up

We need react-query , of course:

yarn add react-query

Then we need to use the provider, do this at your root file:

import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();

<React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>

The QueryClient is created with const queryClient = new QueryClient();. This creates a new instance of the QueryClient that can be used to fetch and cache data.

The QueryClientProvider is a component that allows the QueryClient instance to be used throughout the application. The client prop is used to pass the QueryClient instance to the QueryClientProvider.

Finally, the App component is wrapped in the QueryClientProvider, which makes the QueryClient instance available to all of the child components of App.

Observer

To determine when the browser should fetch new data, we require a certain logic. This involves triggering a callback whenever the user scrolls to a particular point on the page. Let's write a hook for this:

export default function useIntersectionObserver({
  root,
  target,
  onIntersect,
  threshold = 1.0,
  rootMargin = "0px",
  enabled = true,
}) {
  React.useEffect(() => {
    if (!enabled) {
      return;
    }

    const observer = new IntersectionObserver(
      (entries) =>
        entries.forEach((entry) => entry.isIntersecting && onIntersect()),
      {
        root: root && root.current,
        rootMargin,
        threshold,
      }
    );

    const el = target && target.current;

    if (!el) {
      return;
    }

    observer.observe(el);

    return () => {
      observer.unobserve(el);
    };
  }, [target.current, enabled]);
}

This code defines a custom hook named useIntersectionObserver that's used to observe when a certain element intersects with another element, typically the viewport. The hook uses the IntersectionObserver API to detect when the element becomes visible and triggers a callback function when it does.

The hook accepts an object as its argument with properties such as root, target, onIntersect, threshold, rootMargin, and enabled. These properties are used to configure the IntersectionObserver.

The useEffect hook is used to create and destroy the IntersectionObserver when the component is mounted and unmounted respectively. It also watches for changes in the target.current and enabled properties, and only creates the observer if the enabled flag is set to true.

The observer is created using the IntersectionObserver constructor and is passed a callback function that is triggered whenever an intersection is detected. This function checks if the observed element (target.current) is intersecting with another element, such as the viewport. If it is, the onIntersect callback function is called.

The observer is then attached to the observed element using the observer.observe(el) method, and the observer is removed from the observed element when the component is unmounted using the observer.unobserve(el) method.

Implementation

const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery(
    "starwars",
    async ({ pageParam = "https://swapi.dev/api/people/" }) =>
      await fetch(pageParam).then((res) => res.json()),
    {
      getNextPageParam: (lastPage) => lastPage.next ?? false,
    }
  );

  const loadMoreButtonRef = React.useRef();

  useIntersectionObserver({
    target: loadMoreButtonRef,
    onIntersect: fetchNextPage,
    enabled: hasNextPage,
  });

First I found an API in the internet to get Star Wars characters (lucky me ), okay let's breakdown the code

  1. useInfiniteQuery Hook: The useInfiniteQuery hook from React Query is used to fetch and manage the data for the "starwars" query. It takes three arguments:

    • A query key (in this case, "starwars") to uniquely identify the query in the cache.
    • An asynchronous function that fetches and returns the data. In this case, it fetches data from the SWAPI using the fetch function, with the pageParam as the URL. If pageParam is not provided, it defaults to "https://swapi.dev/api/people/".
    • An options object containing the getNextPageParam function which determines the next page URL based on the response of the last page. It checks the next property of the lastPage object and returns it if it exists, otherwise, it returns false.

The hook returns an object containing properties such as data, fetchNextPage, hasNextPage, and isFetchingNextPage.

  1. React useRef Hook: The React.useRef() hook is used to create a mutable ref object (loadMoreButtonRef) that can be passed as a ref attribute to a DOM element (e.g., a "Load More" button).

  2. useIntersectionObserver Custom Hook: This custom hook utilizes the Intersection Observer API to detect when the loadMoreButtonRef element comes into the viewport

Conclusion

In conclusion, infinite loading can be a challenging aspect to implement in React applications, but the React Query library simplifies the process by providing an efficient way to manage data fetching and caching. By utilizing custom hooks such as useIntersectionObserver, developers can easily observe when an element comes into the viewport and trigger additional data fetching as needed. This allows for smooth and performant infinite loading experiences in web applications, meeting user expectations and improving the overall experience. With the help of React Query and a solid understanding of hooks, handling infinite loading in React applications becomes a much more manageable task.

Don't worry if this article is too obscure for you, check these out:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK