0

I am using a custom hook useInfiniteFetchSearch to fetch and search data for a infinite scroll component built using react-infinite-scroll-component.

The hook makes an API call and sets the data in the state using setData. Currently, I am using refreshData() method to refresh the data again when an item is deleted from the list.

However, I am not satisfied with this solution as it calls the API again even though I already have the data. Is there a more efficient way to refresh the data and update the infinite scroll component without making another API call?

Here is my custom hook implementation:

import { useState, useEffect, useRef } from "react";
import axios from "axios";

const useInfiniteFetchSearch = (api, resultsPerPage, sort = null) => {
  const [data, setData] = useState([]);
  const [hasMore, setHasMore] = useState(true);
  const [page, setPage] = useState(2);
  const [loading, setLoading] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");

  const searchTermRef = useRef(null);

  useEffect(() => {
    const searchData = async () => {
      try {
        setLoading(true);

        let query = `${api}${
          searchTerm === "" ? `?` : `?search=${searchTerm}&`
        }page=1`;

        query = sort ? `${query}&sort=${sort}` : query;

        const result = await axios.post(query);
        const fetchedData = result.data;

        setData(fetchedData);
        setPage(2);
        setHasMore(fetchedData.length === resultsPerPage);
      } catch (error) {
        console.error(error);
      } finally {
        setLoading(false);
      }
    };
    searchData();
  }, [searchTerm, api, resultsPerPage, sort]);

  const refreshData = async () => {
    try {
      setLoading(true);

      let query = `${api}${
        searchTerm === "" ? `?` : `?search=${searchTerm}&`
      }page=1`;

      query = sort ? `${query}&sort=${sort}` : query;

      const result = await axios.post(query);
      const fetchedData = result.data;

      setData(fetchedData);
      setPage(2);
      setHasMore(fetchedData.length === resultsPerPage);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  };

  const fetchMore = async () => {
    try {
      setLoading(true);

      let query = `${api}?search=${searchTerm}&page=${page}`;
      query = sort ? `${query}&sort=${sort}` : query;

      const result = await axios.post(query);
      const newData = result.data;

      setData((prev) => [...prev, ...newData]);
      setPage(page + 1);
      setHasMore(newData.length === resultsPerPage);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  };

  const handleSearch = async (e) => {
    e.preventDefault();
    setSearchTerm(searchTermRef.current.value);
  };

  const handleDelete = async (e, itemId) => {
    try {
      await axios.delete(`${api}${itemId}`);
      setData((prevData) => prevData.filter((item) => item.id !== itemId));

      refreshData();
    } catch (error) {
      console.log(error);
    } finally {
    }
  };

  return {
    state: { data, hasMore, loading, searchTermRef, searchTerm },
    handlers: {
      fetchMore,
      setSearchTerm,
      handleSearch,
      handleDelete,
    },
  };
};

export default useInfiniteFetchSearch;

I am using this hook in my component:

    const { state, handlers } = useInfiniteFetchSearch("/api/guides/search", 5);
    
    const { data, hasMore, loading, searchTermRef, searchTerm } = state;
    const { fetchMore, handleSearch, setSearchTerm, handleDelete } = handlers;
    
    .... 
    
    <InfiniteScroll
      dataLength={data.length}
      next={fetchMore}
      hasMore={hasMore}
      scrollableTarget="scrollableDiv"
      loader={
        <div className="flex justify-center items-center mx-auto">
          <Loader />
        </div>
      }
    >
      <div className="space-y-1">
        {data &&
          data.map((item, index) => (
            <GuidesItem
              key={index}
              guide={item}
              handleDelete={handleDelete}
            />
          ))}
      </div>
    </InfiniteScroll>

                

I would appreciate any suggestions or solutions to this problem, thank you!

Abhilash
  • 43
  • 1
  • 8

0 Answers0