I am struggling to find a pattern that works for an infinite scroll component I am working on for reference I am using the react-intersection-observer
hook. The problem is that my fetchData
function is being called twice when the inView
state is true. I have tried quite a few solutions and none of them seem to work. The flow seems to be:
- Page loads
inView
is false. - User scrolls
inView
becomes true. fetchData
is asynchronously called and useEffect ends.res
is finally returned andsetQueryData
finally updates the state.- This triggers the
useEffect
to execute again but since the data has just been set, it hasn’t been rendered yet and pushed theinView
linked component down out of the way. - Since
inView
is stilltrue
anotherfetchData
is executed.
It seems like I need to make inView
false immediately after the useEffect
is run but not sure if this possible or correct, any advice would be greatly appreciated!
type LoadMoreState = {
data: QueryDatabaseResponse[];
nextCursor: string | undefined;
};
export function LoadMore({ cursor }: { cursor: string }) {
const { ref, inView } = useInView();
const [queryData, setQueryData] = useState<LoadMoreState>({
data: [],
nextCursor: cursor,
});
useEffect(() => {
const fetchData = async () => {
if (inView) {
try {
const res = await getGoodFirstIssues({
page_size: 10,
start_cursor: queryData.nextCursor,
});
setQueryData((prevData) => ({
data: prevData.data.concat(res),
nextCursor: res.next_cursor || undefined,
}));
} catch (error) {
console.log("There was an error fetching the data", error);
}
}
};
fetchData();
}, [inView, queryData]);
2
Answers
removing
queryData
from the dependency array, you prevent the useEffect from running whenqueryData
changes. This should help avoid the double-fetching issue you were experiencing. Additionally, make sure that you’re rendering the LoadMore component properly in your main component tree.If the structure of your component requires using
queryData
within the useEffect, consider using the functional update form ofsetQueryData
to avoid dependency-related issues:The problem is that you need
queryData
inside theuseEffect
, because of thenextCursor
, but it also triggers theuseEffect
, whileinView
is stilltrue
.Store the
next_cursor
in a ref (nextCursorRef
), and remove it from the dependencies of theuseEffect
:I would also refactor this a bit more, to prevent defining and calling
fetchData
ifinView
isfalse
: