Issue
I'm getting images via an API that is fetched in a useEffect
hook.
I want to store a random image into an object array and display it immediately when loading the side.
The problem is the useEffect
hook is executed after rendering so the function which gets the random image throws an error.
const [allImages, setAllImages] = useState([]);
useEffect(() => {
fetch("https://api.imgflip.com/get_memes")
.then((response) => response.json()
.then((data) => setAllImages(data.data.memes));
}, []);
const [memes, setMemes] = useState([
{ img: getRandomImg() },
]);
function getRandomImg() {
const randomIndex = Math.floor(Math.random() * allImages.length);
console.log("3");
return allImages[randomIndex].url;
}
First thought was to just return the getRandomImg
function if there are no images but nothing is displayed then.
function getRandomImg() {
if (allImages.length === 0) return;
const randomIndex = Math.floor(Math.random() * allImages.length);
console.log("3");
return allImages[randomIndex].url;
}
I found a solution that works by adding another useEffect
with a dependencie on allImages
.
useEffect(() => {
fetch("https://api.imgflip.com/get_memes")
.then((response) => response.json())
.then((data) => setAllImages(data.data.memes));
}, []);
useEffect(() => {
if (allImages.length > 0) {
addImage();
}
}, [allImages]);
const [memes, setMemes] = useState([]);
function getRandomImg() {
const randomIndex = Math.floor(Math.random() * allImages.length);
console.log("3");
return allImages[randomIndex].url;
}
const addImage = () => {
setMemes((prevMemes) => [
...prevMemes,
{
img: getRandomImg(),
},
]);
};
But this seems more like a workaround and this is sometimes adding two pictures instead of one.
Is there any way to get this to work?
Solution
Your proposed solution is fine, I would do it this way:
const [allImages, setAllImages] = useState([]);
const [memes, setMemes] = useState([])
useEffect(() => {
fetch("https://api.imgflip.com/get_memes")
.then((response) => response.json()
.then((data) => {
setAllImages(data.data.memes)
const randomIndex = Math.floor(Math.random() * allImages.length);
setMemes([{img: data.data.memes[randomIndex].url}])
// do not use allImages in setMemes, as setState is async
// and the new state of allImages will not be ready yet.
});
}, []);
If you would need the images to be ready before the page is rendered, you can use useLayoutEffect as proposed by Sebastian.
Answered By - Fide
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.