Amit
Amit

Reputation: 111

Changing color every second using React Hooks

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

Answers (3)

Tushar Beladiya
Tushar Beladiya

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

w3Abhishek
w3Abhishek

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

CertainPerformance
CertainPerformance

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

Related Questions