I currently have a function that loads information from the backend when I scroll to the bottom of a screen. The problem is that when I scroll to the bottom, it’ll call the function multiple times when I only want it to run once.
The function I want to run:
const loadProgramList = () => {
refreshToken()
.then((refresh) => {
return fetch("http://localhost:5000/program/load-program-list", {
method: "POST",
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${Cookies.get("accessToken")}`,
},
body: JSON.stringify({ index: index }),
});
})
.then((response) => {
if (!response.ok) {
return response.json().then((data) => {
throw { error: data.error, status: response.status };
});
}
return response.json();
})
.then((data) => {
if (data.success) {
setPrograms((prevPrograms) => {
return prevPrograms.concat(data.programs);
});
setIndex((prevIndex) => {
return prevIndex + 10;
});
}
})
.catch((error) => {
if (error.response === 401) {
Cookies.remove("accessToken");
Cookies.remove("refreshToken");
window.location.reload();
ctx.setLoginModal(true);
ctx.setStatus("Session timed out: You have been logged out");
} else {
navigate("/error", {
state: { error: error.error, status: error.status },
});
}
});
};
I’m using useEffect() to check when the user has reached the bottom of the screen:
useEffect(() => {
loadProgramList();
const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
loadProgramList();
}
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, [index]);
How can I make sure the function only runs once?
2
Answers
loadProgramList
will run every time when theindex
has changed.When the scroll reach to the bottom your scroll event callback function will be fired and run
loadProgramList
. And it hassetIndex
logic. So this function will change yourindex
state which is a trigger of youruseEffect
so theuseEffect
will be fired but you haveloadProgramList
in your effect callback function. So it will executeloadProgramList
again.My suggestion is, get rid of the first
loadProgramList
in your effect. If you need to call this function in initial rendering you might want to execute this function only when the first time rendering.You could use
useRef
for this. Something like this.So, if I understand correctly, you want to implement an infinite scroll that loads data when you reach the bottom of the screen.
I don’t understand why you put the scroll event inside
useEffect
forindex
. You need to separate these two things.My suggestion is to add the scroll event handler one time when the component mounts:
And load the new content whenever
index
changes:Also, it might be a good idea to debounce or throttle your scroll event handler for a better performance.