kahonmlg
kahonmlg

Reputation: 4039

state variable scope no access react timeInterval

I am trying to access to intervalId "useState" variable inside of a timeInterval function. But the scope is not working properly. intervalId is always null inside ot the timeInterval function, that means that it does not about delay of value assignation.

    export function useLocalCommands(length, id) {
    const [intervalId, setIntervalId] = useState(null)
    const [currentIndex, setCurrentIndex] = useState(10)
    const [timeInterval, setTimeInterval] = useState(Constants.READING.READING_TIME_INTERVAL)

    let pauseReading = () => {
        console.log("pause:" + intervalId)
        clearInterval(intervalId)
    }

    let startReading = () => {
        console.log("play")
        pauseReading()
        if (currentIndex < length) {
            setIntervalId(setInterval(() => {
                setCurrentIndex((index) => {
                    if (index < length) {
                        if (id && index % 40 === 0) {
                            Meteor.call('myBooks.updateIndex', id, index, (err, res) => {
                                // show a toast if err 
                            })
                        }
                        return index + 1
                    } else {
                        console.log("pauseReading: " + intervalId)
                        pauseReading();
                    }
                })
            }, timeInterval))

        }
    }
}

Thanks you, Best.

Upvotes: 1

Views: 48

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281656

IntervalId is being used from closure which is why when the setInterval runs, the values being takes at the time of declaration. However setIntervalId triggeres a state update and even though the value of state is updated, your timerId within setInterval function continues to point to the old state that it used from closure.

Instead of using state, you can make use of useRef to store the timerId. Since refs are mutated, they aren't affected by closure

export function useLocalCommands(length, id) {
    const intervalId = useRef(null)
    const [currentIndex, setCurrentIndex] = useState(10)
    const [timeInterval, setTimeInterval] = useState(Constants.READING.READING_TIME_INTERVAL)

    let pauseReading = () => {
        console.log("pause:" + intervalId.current)
        clearInterval(intervalId.current)
    }

    let startReading = () => {
        console.log("play")
        pauseReading()
        if (currentIndex < length) {
            intervalId.current = setInterval(() => {
                setCurrentIndex((index) => {
                    if (index < length) {
                        if (id && index % 40 === 0) {
                            Meteor.call('myBooks.updateIndex', id, index, (err, res) => {
                                // show a toast if err 
                            })
                        }
                        return index + 1
                    } else {
                        console.log("pauseReading: " + intervalId.current)
                        pauseReading();
                    }
                })
            }, timeInterval);

        }
    }
}

Upvotes: 1

Related Questions