skip to Main Content

I should create an infinite scroll in reactJs having a JSON with data in it. Could you help me?

I would like to do it from scratch and not with some library

{data?.map((conto) => {

  return (
    <Suspense key={conto._uid} fallback={<p>Loading...</p>}>
      <Conto blok={conto} data={data} ITEuro={ITEuro} deposit={deposit} handleToggleFavourite={handleToggleFavourite} isFavourited={isFavourited} depositQuantity={depositQuantity} />
    </Suspense>
  )

})}

I load the JSON like this for now, but I would like a maximum number of ids to be loaded until we reach the bottom of the page and more are loaded

2

Answers


  1. Chosen as BEST ANSWER

    I managed to solve it this way

    export default function App() {
      const [limiteData, setLimiteData] = useState([]);
      const [page, setPage] = useState(1);
      const [isLoading, setIsLoading] = useState(false);
    
      const fetchData = useCallback(() => {
         setIsLoading(true);
    
         // Simula un ritardo di caricamento per mostrare l'indicatore di caricamento
         setTimeout(() => {
           const newData = data.slice((page - 1) * 5, page * 5); // Carica 10 elementi per pagina
           setLimiteData((prevData) => [...prevData, ...newData]);
           setPage((prevPage) => prevPage + 1);
           setIsLoading(false);
         }, 1000);
      }, [page]);
    
      useEffect(() => {
        fetchData();
      }, [fetchData]);
    
      return (
        <div className="App">
          {limiteData.map((blok) => {
            return (
              <div key={blok._uid}>
                <h1>{blok.name}</h1>
              </div>
            );
          })}
          <Suspense fallback={<p>Loading...</p>}>
            {isLoading && <p>Loading...</p>}
           </Suspense>
        </div>
      );
    }
    

    1. Set up the initial state with a maximum number of items to load and the current number of loaded items.
    2. Add an event listener to track the scroll position and trigger loading more items when the user reaches the bottom of the page.
    3. Update the state with new items and render them accordingly.

    Here’s a sample implementation of the infinite scroll:

    import React, { useState, useEffect, useRef, Suspense } from 'react';
    
    // Your JSON data (Replace this with your actual data)
    const jsonData = [
      // ... your data here
    ];
    
    const InfiniteScroll = () => {
      const [data, setData] = useState(jsonData.slice(0, 10)); // Initial data to load
      const [loadedItems, setLoadedItems] = useState(10); // Initial number of loaded items
      const containerRef = useRef(null);
    
      // Function to load more items
      const loadMoreItems = () => {
        const nextItems = jsonData.slice(loadedItems, loadedItems + 10);
        setData((prevData) => [...prevData, ...nextItems]);
        setLoadedItems((prevLoadedItems) => prevLoadedItems + 10);
      };
    
      // Function to check if the user has reached the bottom of the page
      const handleScroll = () => {
        const container = containerRef.current;
        if (
          container.scrollHeight - container.scrollTop ===
          container.clientHeight
        ) {
          loadMoreItems();
        }
      };
    
      // Attach the scroll event listener on component mount
      useEffect(() => {
        const container = containerRef.current;
        container.addEventListener('scroll', handleScroll);
        return () => container.removeEventListener('scroll', handleScroll);
      }, [loadedItems]); // <-- Add loadedItems to the dependency array
    
      return (
        <div ref={containerRef} style={{ height: '500px', overflowY: 'auto' }}>
          {data.map((conto) => (
            <Suspense key={conto._uid} fallback={<p>Loading...</p>}>
              {/* Render your Conto component here */}
            </Suspense>
          ))}
        </div>
      );
    };
    
    export default InfiniteScroll;
    

    In this implementation, jsonData represents your complete JSON data. We start by loading the first ten items initially, and then, as the user scrolls down and reaches the bottom of the container (div with ref={containerRef}), we load ten more items until we have loaded all the data. Make sure to replace the comment inside the .map() function with your actual rendering of the Conto component with the appropriate props.

    Remember to adjust the number of items to load at once or tweak the behavior according to your specific use case. Also, note that the code assumes that your Conto component is renderable using the Suspense component. If you’re using asynchronous components, it’s essential to wrap them with Suspense.

    Edit:

    In this revised implementation, I’ve added loadedItems to the dependency array of the useEffect hook. This means that the event listener will be reattached whenever the value of loadedItems changes. By doing this, we ensure that the handleScroll function is aware of the updated loadedItems value and will trigger the loading of more items correctly when the user reaches the bottom of the container.

    This should resolve the issue, and the code should now load more items as you scroll to the bottom of the page.

    Edit 2:

    import "./styles.css";
    import data from "./data";
    import { useState, useEffect, useRef } from "react";
    
    export default function App() {
      const [limiteData, setLimiteData] = useState(data.slice(0, 10)); // Initial data to load
      const [loadedItems, setLoadedItems] = useState(10); // Initial number of loaded items
      const containerRef = useRef(null);
    
      // Function to load more items
      const loadMoreItems = () => {
        const nextItems = data.slice(loadedItems, loadedItems + 10);
        setLimiteData((prevData) => [...prevData, ...nextItems]);
        setLoadedItems((prevLoadedItems) => prevLoadedItems + 10);
      };
    
      // Function to check if the user has reached the bottom of the page
      const handleScroll = () => {
        const container = containerRef.current;
        if (container.scrollHeight - container.scrollTop <= container.clientHeight) {
          loadMoreItems();
        }
      };
    
      // Attach the scroll event listener on component mount
      useEffect(() => {
        const container = containerRef.current;
        container.addEventListener("scroll", handleScroll);
    
        return () => container.removeEventListener("scroll", handleScroll);
      }, [loadedItems]); // <-- Add loadedItems to the dependency array
    
      return (
        <div ref={containerRef} className="App" style={{ height: "400px", overflowY: "auto" }}>
          {limiteData.map((blok) => {
            return (
              <div key={blok._uid}>
                <h1>{blok.name}</h1>
              </div>
            );
          })}
        </div>
      );
    }
    

    I finally figured it out. In the handleScroll function, the condition to check whether the user has reached the bottom should use the less than or equal to <= operator instead of just the equal to === operator. This change will ensure that the loadMoreItems function is triggered when the user is very close to the bottom of the container, not just at the exact pixel when the height matches.

    I’ve also added inline styles to the container div to specify its height and allow vertical scrolling so that the infinite scroll works as expected.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search