I have implemented infinte scroll to fetch more data whenever user reaches to the bottom of page. It seems to work fine but I have special condition.
When the page renders first time I get the response as :
count: 47
next: "http://localhost:8000/api/user/groups/56/users/?limit=20&offset=20"
previous: null
results: [{id: "79", email: "priyanka+LarryLo@emembler.com", first_name: "Larry", last_name: "Lo",…},…]
Where count represents the total number of items in array, in "next" string limit is set to 20 that means I get the maximum 20 items for each api call and offest shows that, to get next items I have to give offset "20" in next api call. Once all the data is fetched "next" value will be null, so I have made condition something like if "next" value is null dont give the call to api, but api call is given.
Reducer code to store data that is being fetched:
case GET_MEMBERS_OF_GROUP: {
newState["nextMembers"] =action.payload.response.next;
if (action.payload.response.results) {
let newArray = newState["members"].concat(
action.payload.response.results
);
newState["members"] = newArray;
} else {
newState["members"] = action.payload.response.results;
}
if(action.payload.page == 0){
newState["members"] = action.payload.response.results
}
return newState;
}
I have anothe reducer to update the offset that will be provided to next api call:
case SHOW_NEXT_MEMBERS: {
newState["pageOfmembers"] = newState["pageOfmembers"] + action.payload.nextMembers;
return newState;
}
Infinite scroll implementation, where offset is not getting incremented and also when "next" value is null api call is given:
const [nextmembers, setNextmembers] = useState()
useEffect(() => {
setNextmembers(data.nextMembers)
},[data.nextMembers])
useEffect(() => {
const event = window.addEventListener('scroll', () => {
if ((window.innerHeight + window.scrollY) == document.body.scrollHeight ) {
if(nextmembers&& window.location.href.includes("/members")){
dispatch({
type: SHOW_NEXT_MEMBERS,
payload: {
nextMembers: 20,
},
})
setTimeout(() => {
dispatch(EMDoGetMembersOfGroupAction({id:data.singleGroup.id ? data.singleGroup.id : window.sessionStorage.getItem("GroupId"), limit:data.pageOfmembers}))
},500)
}
}
})
return () => window.removeEventListener('scroll', event);
}, [nextmembers])
So this may not be the whole solution, but part of the problem is how you use addEventListener and removeEventListener. You need to store the event handling function into a variable and then use that variable with addEventlistener and removeEventListener.
const [nextmembers, setNextmembers] = useState()
useEffect(() => {
setNextmembers(data.nextMembers)
},[data.nextMembers])
const handleScroll = useCallback(() => {
// all the logic in that anonymous function goes here
if ((window.innerHeight + window.scrollY) == document.body.scrollHeight ){
// ...
}
}, [!!nextMembers])
useEffect(() => {
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [handleScroll])