I am calling setState
within useEffect
and it’s triggering infinitely. I’m having a hard time understanding why. The problem is with the third useEffect
that is dependent on picked
.
import GameCSS from './game.module.css'
import Dog from "./dog/dog"
import { useState, useEffect, useRef } from 'react'
function Game () {
const [dogs, setDogs] = useState<string[]>([]);
const [picked, setPicked] = useState<boolean>(false);
const [fave, setFave] = useState<string>('');
const [images, setImages] = useState<string[]>();
useEffect(() => {
fetch('https://dog.ceo/api/breeds/image/random/10')
.then(response => response.json())
.then(data => setDogs(data.message));
}, []);
useEffect(() => {
setImages([dogs[0], dogs[1]]);
}, [dogs]);
useEffect(() => {
setImages([dogs[1], dogs[2]]);
}), [picked];
if (images) {
return (
<>
<div className={GameCSS.dogs}>
<Dog
image={images[0]}
setFave={setFave}
picked={picked}
setPicked={setPicked}
/>
<Dog
image={images[1]}
setFave={setFave}
picked={picked}
setPicked={setPicked}
/>
</div>
</>
)
}
}
export default Game
import DogCSS from './dog.module.css'
interface info {
image: string;
setFave: (image: string) => void;
picked: boolean;
setPicked: (toggle: boolean) => void
}
function Dog (props:info) {
function setFave() {
props.setFave(props.image);
props.setPicked(!props.picked);
}
return (
<img
className={DogCSS.image}
src={props.image}
onClick={setFave}
>
</img>
)
}
export default Dog
Warning Message: game.tsx:23 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside
useEffect, but useEffect either doesn’t have a dependency array, or
one of the dependencies changes on every render.
at Game (http://127.0.0.1:5173/src/components/game/game.tsx?t=1689969940032:23:27)
at div
at App
What is supposed to happen is that when the user clicks on an image it toggles the picked
state and triggers the images
to update.
I tried removing picked
dependency from the offending useEffect
and that did not solve it. I tried doing something other than setImages
and that fixes it, but what I need to do is update the images
array when the picked
flag is toggled so I need to find a way or redesign my solution. I tried to figure out how to set the offending useEffect
to not run on the first render, but I became a bit overwhelmed and didn’t understand.
2
Answers
Besides the suboptimal design, the infinite useEffect behavior is caused by a misplaced bracket as pointed out in the comments. First snippet is incorrect, second is correct. My friend pointed out that chatGPT can be good at finding these bugs and it did find it when I tried it there.
There is no need of second and third useEffect in your code you can call setImages in first useEffect where you call setDogs.
and also no need to pass all the props to component you can just pass the image and on an onClick method to get the event.
I optimize your code below
Game
Dog