meet vaghsiya
meet vaghsiya

Reputation: 230

how to use setInterval without useEffect in react

if i used setInterval(line 15) without useEffect than it gives result 2^n-1(0,1,3,7,15,31,63...) instead of(0,1,2,3,4,..) . so i have some question
1)why i am getting that output when I directly called setInterval without useeffect 2)is there any way if I change setCount(line 9) and its gives correct output by use setInterval directly without useEffect(as I did) 3) if the use of setInterval is not possible without useEffcet than why it is not possible?

if i put setInterval in useEffect and render initially once( line 12,13,14) than it gives correct output..... but I do not get the correct output when I use directly setInterval. what is diff bet them?
in both cases, I call setInterval once but the output is diff.

import React, {useEffect, useState } from 'react'
    
    export default function IncorrectDependency() {
    
    const [count,setCount]=useState(0)
    
    const inc=()=>{
        // console.log(count)
        setCount(preVal=>preVal+1)
    //    setCount(count+1)
    }
    // useEffect(()=>{
    //     setInterval(inc,1000)},[]
    // )
    setInterval(inc,1000)
    
        return (
            <div>
                <h1>{count}</h1>
               
            </div>
        )
    }

Upvotes: 0

Views: 2792

Answers (3)

frankie
frankie

Reputation: 11

Dan Abramov explains why this isn't a good idea:

"it’s not the idiomatic way to do it. eg it won’t work correctly if you have multiple instances of the same component. it breaks the rules — it does a side effect (setInterval) during rendering, which the page said you should not do :) once you break the rules, all bets are off"

https://twitter.com/dan_abramov/status/1577395235340095501?s=20&t=nNnYyjLvHs5by_dqF5l8zg

Upvotes: -1

Kalhan.Toress
Kalhan.Toress

Reputation: 21901

When we do a set state, functional components will re-execute from top to bottom, how ever when we use useState, useCallbacks etc.. they will not re-initialize as variables, functions,

So in this case, setInterval will re-initialize on each and every setCount, because of the state got changed,

step by step

  • in the 1st second there will be one setInterval, and call setCount and component is ready to rerender
  • when re-redering, start executing functional component from top-to-bottom it sees setInterval again and it will trigger it, so now we have two setIntervals
  • so on it will add multiple setIntervals on each second, because we don't clear it, so you should see the number printed in the browser will not take a second, but less than a second when time goes by.

You can achieve the expected result without useEffect by clearing the previous interval on each re-render which is happen due to setCount

create a variable to hold the set interval, code

const interval = null;
//this should be declare out side the component,
//because if we declare it inside the component it will redeclare,
//and the reference to the previous setInterval will be lost in that case no-way to clear the setInterval.
export default function IncorrectDependency() {
    ....
    if (interval) {
        clearInterval(interval);
    }

    interval = setInterval(inc, 1000);
    ....
 }

alternatively react has a hook which can hold the same variables without re-initializing on each renderings, check it out useRef

here is a code-demo

const intvl = useRef(null);
....

if (intvl?.current) {
    clearInterval(intvl.current);
}

intvl.current = setInterval(inc, 1000);
.....

Upvotes: 7

Alok Takshak
Alok Takshak

Reputation: 280

when you directly use setInterval what is happening as this is a function it will be called on state change so again a setInterval will be triggered and so on which actually give you the incorrect result, so you shouldn't use setInterval without use effect, also on unmount you should clearthe interval

Upvotes: 1

Related Questions