Reputation: 111
I'm trying to change the color of a SVG structure from red to white and white to red using React Hooks. The problem is that after a few seconds the color starts changing rapidly instead of every second. I'm not understanding where I'm going wrong in the code.
Here is the useState.
const[rectColor, rectColorSet] = useState('red')
And the useEffect for changing the color.
useEffect(() => {
if(rectColor === 'red'){
let timer = setInterval(() => {
rectColorSet('white')
}, 1000)
}
// console.log('timer',timer)
else if(rectColor ==='white'){
let timer = setInterval(() => {
rectColorSet('red')
}, 1000)
}
})
And this is the place where I use the state which contains color.
d={`
M-0.20 0 L-0.20 0.30 L0.20 0.30 L0.20 0 L-0.20 0
Z`}
fill={props.value ? "green" : rectColor}
/>
}
Upvotes: 2
Views: 2731
Reputation: 46
After a few seconds, the color starts changing rapidly instead of every second because you put [] in useEffect.
If you want to run an useEffect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as the second argument in useEffect hook.
And You should use setTimeout()
intend of setInterval()
So you should write your useEffect like this:
const [red, setRed] = useState(true);
useEffect(() => {
const intervalID = setTimeout(() => {
setRed(red => !red);
}, 1000);
return () => clearInterval(intervalID);
}, []);
Upvotes: 2
Reputation: 137
You actually need to replace setInterval()
with setTimeout()
and rather than declaring everthing seperately use OR in the conditional and clean up the code.
Upvotes: 0
Reputation: 370759
Every render's setting a new interval. Use setTimeout
instead of setInterval
, and don't forget to clean up the effects:
useEffect(() => {
if (rectColor === 'red' || rectColor === 'white') {
const timeoutID = setTimeout(() => {
rectColorSet(rectColor === 'red' ? 'white' : 'red');
}, 1000);
return () => clearTimeout(timeoutID);
}
});
Or toggle between a boolean instead of using a string for state. If you add other state that might change, using a single interval when the component mounts might be easier to manage:
const [red, setRed] = useState(true);
useEffect(() => {
const intervalID = setInterval(() => {
setRed(red => !red);
}, 1000);
return () => clearInterval(intervalID);
}, []);
Upvotes: 4