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!