bobby_turks
bobby_turks

Reputation: 95

Infinite Scroll with react and api calls updating state

I am trying to take a tutorial for an infinite scroll using vanilla javascript and use react. To get a better understanding of how react works. I can fetch the data display the initial data. Scroll to the bottom fetch more data but the data just over riders the current data. Also I can only fetch up to page 2 I would love if someone could point me in the right direction.

import React, { useState, useEffect } from "react";

import "./App.css";

function App() {
  const [posts, setPosts] = useState([{}]);
  const [isFetching, setIsFetching] = useState(false);
  let limit = 5;
  let page = 1;

  const getPosts = async () => {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}`
    );
    const data = await response.json();
    setPosts(data);
    console.log(data);
  };

  function handleScroll() {
    if (
      window.innerHeight + document.documentElement.scrollTop !==
      document.documentElement.offsetHeight
    )
      return;
    setIsFetching(true);
  }

  function getMorePosts() {
    setTimeout(() => {
      page++;
      setPosts([{ ...posts }], posts);
      setIsFetching(false);
    }, 2000);
  }

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  useEffect(
    () => {
      getPosts();
    }, //eslint-disable-next-line
    []
  );
  useEffect(() => {
    if (!isFetching) return;
    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 && (
        <div className="loader">
          <div className="circle"></div>
          <div className="circle"></div>
          <div className="circle"></div>
        </div>
      )}
    </div>
  );
}

export default App;

Upvotes: 3

Views: 13199

Answers (1)

Daniel Kobe
Daniel Kobe

Reputation: 9825

One thing I noticed off the bat is that page is not in the state so it will be reset on every render. Also since limit is not changing you should use a constant.

Why are you initializing this to an array with an empty object in it? useState([{}]); just use an empty array

Also I'm not sure what you are intending to do here setPosts([{ ...posts }], posts); but if you want to append the new posts while copying the objects you should do this

  const getPosts = async () => {
    setIsFetching(true)
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}`
    );
    const data = await response.json();
    setPosts([...posts, ...data]);
    setIsFetching(false)
  };

  function getMorePosts() {
    setTimeout(() => {
      setPage(page++)
      getPosts();
    }, 2000);
  }

Upvotes: 4

Related Questions