I am trying to make an infinite scrolling list of pokemons in react using IntersectionObserverAPI where i have an empty div element at the end of the page and when it comes to view more pokemons are fetched from the API.
But this uses the pokemons array (which is the state representing all the pokemons on the page) for the offset to load the data using the length property. But the length property inside the loadPokemons function is always 0 i don’t know why. I have tried tried many things but same thing happens.
This is the Pokemons component -:
In this whenever the observer intersects it calls the loadPokemons function which fetched the data using the fetchPokemons function by passing in the offset as pokemons.length but this always gives 0 i don’t know why. Please help.
import { useEffect, useRef, useState } from "react";
import Pokemon from "./Pokemon";
import { type Pokemon as PokemonDataType } from "./types";
type ResponseType = {
count: number,
next: string,
previous: string | null,
results: PokemonDataType[]
}
const fetchPokemons = async (url: string, offset: number, limit: number): Promise<PokemonDataType[]> => {
const response = await fetch(`${url}?offset=${offset}&limit=${limit}`);
const data: ResponseType = await response.json();
const pokemons = data.results.map(result => { return { name: result.name, url: `https://img.pokemondb.net/artwork/${result.name}.jpg` } });
return pokemons;
}
const url = "https://pokeapi.co/api/v2/pokemon";
export default function Pokemons() {
const [pokemons, setPokemons] = useState<PokemonDataType[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const myRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const loadInitialPokemons = async () => {
const initData = await fetchPokemons(url, 0, 12);
setPokemons(initData);
const observer = new IntersectionObserver((entries) => {
for (let entry of entries) {
if (entry.isIntersecting && !isLoading) {
loadPokemons();
}
}
});
if (myRef.current) {
observer.observe(myRef.current);
}
}
loadInitialPokemons();
}, []);
const loadPokemons = async () => {
if (isLoading) return;
setIsLoading(true);
const morePokemons = await fetchPokemons(url, pokemons.length, 5);
setPokemons(prevPokemons => [...prevPokemons, ...morePokemons]);
setIsLoading(false);
}
return (
<div>
<ul>
{pokemons.map((pokemon, idx) => <Pokemon key={idx} name={pokemon.name} url={pokemon.url} />)}
</ul>
{isLoading && <h4>Loading....</h4>}
<div ref={myRef}></div>
</div>
);
}
This is the Pokemon type alias
export type Pokemon = {
url: string,
name: string
}
This is the Pokemon component -:
import { type Pokemon } from "./types";
export default function Pokemon({ name, url }: Pokemon) {
return (
<li style={{ display: "block", width: "100%" }}>
<img src={url} />
<h3 style={{ textAlign: "center" }}>{name}</h3>
</li>
);
}
This is the App component -:
import './App.css';
import Pokemons from './Pokemons';
function App() {
return (
<>
<Pokemons />
</>
);
}
export default App;
At first i initialized the observer api outside the loadInitialPokemons function but it gave the same problem as it gives now with the observerAPI being initialized inside the the function.


