App.jsx
import React, { useState } from "react";
import Pokemon from "./Pokemon";
import Pagination from "./Pagination";
import PokemonList from "./PokemonList";
function App() {
const [nextPage, setnextPage] = useState(
"https://pokeapi.co/api/v2/pokemon?offset=20&limit=20"
);
const [previousPage, setPreviousPage] = useState();
const [CurrentPage, setCurrentPage] = useState(
`https://pokeapi.co/api/v2/pokemon`
);
const [pokemonData, setPokemonData] = useState([]);
const [pokemon, setPokemon] = useState([]);
const paginationNext = () => {
setCurrentPage(nextPage);
};
const paginationPrevious = () => {
setCurrentPage(previousPage);
};
const [loading, setLoading] = useState(true);
const [imgLoader,setImgLoader] = useState(true);
return (
<div className="bg-gray-800 min-h-screen flex justify-center items-center">
<div className="bg-gray-100 p-8 rounded-lg shadow-lg md:h-auto">
<PokemonList pokemonData={pokemonData} pokemon={pokemon} loading={loading} imgLoader={imgLoader}/>
<Pokemon
CurrentPage={CurrentPage}
setPreviousPage={setPreviousPage}
setnextPage={setnextPage}
pokemonData={pokemonData}
setPokemonData={setPokemonData}
setPokemon={setPokemon}
setLoading={setLoading}
loading={loading}
setImgLoader={setImgLoader}
/>
<Pagination
paginationPrevious={previousPage ? paginationPrevious : null}
paginationNext={nextPage ? paginationNext : null}
/>
</div>
</div>
);
}
export default App;
Pokemon.jsx
import React, { useEffect, useState } from "react";
import axios from "axios";
function Pokemon({
setnextPage,
setPreviousPage,
CurrentPage,
setPokemonData,
setPokemon,
setLoading,
loading,
setImgLoader
}) {
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
setPokemonData([]);
setImgLoader(true)
const response = await axios.get(CurrentPage);
setnextPage(response.data.next);
setPreviousPage(response.data.previous);
const pokemon = response.data.results.map((pokemon) => ({
name: pokemon.name.charAt(0).toUpperCase() + pokemon.name.slice(1),
url: pokemon.url,
}));
const pokemonUrl = response.data.results.map((Pokemon) => Pokemon.url);
const pokemonSpriteUrl = pokemonUrl.map((url) => axios.get(url));
const spriteResponse = await Promise.all(pokemonSpriteUrl);
const pokemonData = spriteResponse.map((response) => {
const spriteUrl =
response.data.sprites.versions["generation-viii"]["icons"]
.front_default;
return {
sprite: spriteUrl,
};
});
setPokemon(pokemon);
setPokemonData(pokemonData);
setLoading(false);
setImgLoader(false)
} catch (error) {
console.log(error);
}
};
fetchData();
}, [CurrentPage]);
if (loading) {
return (
<div className="text-blue-700 text-xl font-mono text-center p-2 m-2">
<div className="inline-block animate-spin mr-2">
<div className="size-6 border-t-2 border-blue-700 rounded-full"></div>
</div>
Loading...
</div>
);
}
else {
return null;
}
}
export default Pokemon;
PokemonList.jsx
import React from "react";
import { v4 as uuidv4 } from "uuid";
export default function PokemonList({ pokemonData, pokemon,imgLoader}) {
if (!pokemonData || pokemonData.length === 0) {
return <div></div>;
}
return (
<div className="border-2 border-black flex justify-center h-full">
<div className="flex flex-wrap">
<h1 className="w-full text-center text-4xl font-sans font-bold border-b-2 border-black pb-2 mb-4">
Pokemon Data
</h1>
<ul className="flex flex-wrap justify-center">
{pokemon.map((poke, index) => (
<li
key={uuidv4()}
className="m-2 p-2 text-xl font-serif border-2 border-black w-36 text-center rounded-md bg-gray-200 hover:bg-gray-300 cursor-pointer flex justify-center items-center flex-col"
>{imgLoader == false?(
<div className="text-blue-700 text-xl font-mono text-center p-2 m-2">
<div className="inline-block animate-spin mr-2">
<div className="size-6 border-t-2 border-blue-700 rounded-full"></div>
</div>
</div>):(
<img
src={pokemonData[index].sprite}
alt={poke.name}
className="max-w-full h-auto"
/>
)}
<a href={poke.url} target="_blank">
{poke.name}
</a>
</li>
))}
</ul>
</div>
</div>
);
}
I am trying to put a loading spin in pokemon sprites postion while they are being loaded so when the images appear the loading spin should disappear but only the loading spin is showing not the pokemon images and im using const [imgLoader,setImgLoader] = useState(true);
but im getting no results somehow and even when i set imgLoader to false only the images show but not the image loader i have been trying from the last night idk how to do it can somebody help?
2
Answers
I can see that you have not added finally block while fetching the data.
It is very important to add a finally block which should set the loading to false.As per your code when the data fetching fails the loading will always remain true, so to avoid that add a finally block and set loading to false.
You must paste this code in your function body,above "return"