I'm trying to implement Infinite Scrolling in a React application using the IntersectionObserver API but i'm running into some issues

I'm trying to implement infinite scrolling and it's supposed to work by getting data in pages from the API...and then using the IntersectionObserver API, checking for an intersection between the target Element and the viewport, and when there's one, request the next page and get the data and add it to the previous posts...While experimenting I was able to get it to sort of work but it sometimes keeps requesting for the same page and maybe goes into an infinite loop of requests. I was going to try to create a custom hook for it but because I was also using redux I did something like this:

Here's the post component with the infinite scroll implementation:

const Posts = ({ setCurrentId }) => {

const classes = useStyles()
const dispatch = useDispatch();

const { posts } = useSelector((state) => state.posts);
const { numberOfPages } = useSelector((state) => state.posts);
const { currentPage } = useSelector((state) => state.posts);

const [postsArr, setPostsArr] = useState([posts]);
const [hasMore, setHasMore] = useState(false);
const [pageNum, setPageNum] = useState(1);

useEffect(() => {
    dispatch(getPosts((pageNum)))
    const newPostsArr = postsArr.concat(posts);
    setPostsArr(newPostsArr);
    setHasMore(numberOfPages > 0);
}, [pageNum]);

const { loading } = useSelector((state) => state.posts);

const observer = useRef();
const lastPostElementRef = useCallback((node) => {
    if (observer.current) observer.current.disconnect();
    observer.current = new IntersectionObserver((entries) => {
        if (entries[0].isIntersecting && hasMore) {
            setPageNum((prev) => prev + 1);
        }
        dispatch(getPosts(pageNum));
    });
    if (node) observer.current.observe(node);
    if (currentPage === numberOfPages) setHasMore(false);
}, [hasMore]);

if (!postsArr.length && !loading) return 'No posts found';
else
    return (
        <Grid className={classes.container} container alignItems="stretch" spacing={3}>
            {postsArr[0].map((post, i) => (
                (postsArr.length === i + 1) ? (
                    <Grid key={post._id} ref={lastPostElementRef} item xs={12} sm={6} md={6} lg={3} >
                        <Post post={post} setCurrentId={setCurrentId} />
                    </Grid>
                ) : (
                    <Grid key={post._id} item xs={12} sm={6} md={6} lg={3}>
                        <Post post={post} setCurrentId={setCurrentId} />
                    </Grid>
                )
            ))}
            <div>{loading && <CircularProgress />}</div>
            </Grid>
        )}
export default Posts;

Here's the action that gets dispatched:

export const getPosts = (page) => async (dispatch) => {
try {
    dispatch({ type: START_LOADING })
    const { data: { data, currentPage, numberOfPages } } = await api.fetchPosts(Number(page));

    dispatch({ type: FETCH_ALL, payload: { data, currentPage, numberOfPages } });
    dispatch({ type: END_LOADING })
} catch (error) {
       console.log(error)
    }
}

And then the reducer:

const postReducer = (state = [], action) => {
switch (action.type) {
    case START_LOADING:
        return { ...state, loading: true };
    case END_LOADING:
        return { ...state, loading: false };
    case FETCH_ALL:
         return {
            ...state,
            posts: action.payload.data,
            currentPage: action.payload.currentPage,
            numberOfPages: action.payload.numberOfPages,
            // error: action.payload.error
        };
   default:
            return state;
    }
}
export default postReducer

I don't think there's a need for this but here's the backend API controller function:

const getPosts = async (req, res) => {
const { page } = req.query;

try {
    const LIMIT = 8;
    const startIndex = (Number(page) - 1) * LIMIT; //GET THE STARTING INDEX OF EVERY PAGE
    const total = await postMessage.countDocuments({});

    const posts = await postMessage.find().sort({ _id: -1 }).limit(LIMIT).skip(startIndex);

    res.status(200).json({ data: posts, currentPage: Number(page), numberOfPages: Math.ceil(total / LIMIT) });
} catch (error) {
        res.status(404).json({ message: error.message });
    }
}

posts and postsArr returns undefined and the component returns this error: enter image description here

I hope this is detailed enough and I'd really appreciate a response on what I'm doing wrong or if there's a better way to accomplish my goal.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum