Reputation: 176
I am working on one React infinite scroll component and its working fine and perfectly, only one small issue is that for page number 1, it makes twice the API request, which I do not want and for other pages ex 2,3,4 it makes request only once.
I tried everything but i am unable to modify the code so that for page number 1,it makes only once the request.
How can i make only once the request for page number 1 also ? here is the working code.
import React, { useState, useEffect } from "react";
import axios from "axios";
function Lists() {
const [posts, setPosts] = useState([]);
const [newposts, setNewposts] = useState([]);
const [isFetching, setIsFetching] = useState(false);
const [page, setPage] = useState(1);
const LIMIT = 7;
const getPosts = () => {
axios.get(`https://jsonplaceholder.typicode.com/posts?_limit=${LIMIT}&_page=${page}`)
.then(res => {
setNewposts(res.data);
setPosts([...posts, ...res.data]);
setIsFetching(false);
})
};
const getMorePosts= () => {
setPage(page + 1);
getPosts();
}
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop !==
document.documentElement.offsetHeight
) return;
setIsFetching(true);
}
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
useEffect(() => {
getPosts();
},[]);
useEffect(() => {
if (!isFetching){
return;
}
if( newposts.length > 0 ){
getMorePosts();
}
}, [isFetching]);
return (
<div className="App">
{posts.map((post, index) => (
<div key={index} className="post">
<div className="number">{post.id}</div>
<div className="post-info">
<h2 className="post-title">{post.title}</h2>
<p className="post-body">{post.body}</p>
</div>
</div>
))}
{isFetching && newposts.length > 0 && (
<div style = {{display: "flex", justifyContent:"center"}}>
<div className="spinner-border" role="status">
<span className="sr-only">Loading...</span>
</div>
</div>
)}
</div>
);
}
export default Lists;
Upvotes: 1
Views: 2140
Reputation: 30967
The issue is that setPage
, like any state setter, works asynchronously - it doesn't update the value of page
immediately like it appears you might be expecting it to. The value of page
will only be updated in a subsequent render which is triggered by the state change.
That means that in getMorePosts()
you're not really getting page + 1
, you're just getting page
.
That means on first render you're calling getPosts()
in that other useEffect
, with page
set to 1
, then calling it again when you scroll and call getPosts()
inside the getMorePosts()
call.
Subsequent calls only happen once because getMorePosts()
increments page
in every subsequent render.
As for a fix, a quick one might be to just take page
as an arg to getPosts
, then you can statically call getPosts(1)
on first render and keep the rest of the logic the same but init the page
state to 2
and change the call to getPage(page)
inside getMorePosts()
.
Upvotes: 1