oderfla
oderfla

Reputation: 1797

setInterval not being able to access variables in react

A simple react script:

import React, { useState, useEffect } from 'react';
export default function App() {
    const [indexesArray, setIndexesArray] = useState([]);

    const doit = () => {
        const arr = [];
        for(let i = 0;i<10;i++){
            arr.push(i);
        }
        setIndexesArray(arr);
    }

    useEffect(() => {
        if(!indexesArray.length){
            doit();
            setInterval(function(){
                console.log('indexesArray',indexesArray);
            }, 2000);
        }
        
    }, [indexesArray]);

    return (
      <>
        {indexesArray && JSON.stringify(indexesArray)}
      </>
  );
}

On the page I can see the content of the array. However, printing the array in the console each 2 seconds shows an empty array. What am I missing?

Upvotes: 0

Views: 167

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370679

The indexesArray binding being used by the setInterval is the array that exist in the scope that the interval was created - which is empty. Re-rendering of the components doesn't mutate the existing state - it runs the whole app again, in a whole different scope (but this time with new values returned by useState).

In your effect hook, set the interval only if the array has been populated (and don't forget to clear the interval afterwards).

function App() {
    const [indexesArray, setIndexesArray] = React.useState([]);

    const doit = () => {
        const arr = [];
        for(let i = 0;i<10;i++){
            arr.push(i);
        }
        setIndexesArray(arr);
    }

    React.useEffect(() => {
        if(!indexesArray.length){
            doit();
        } else {
            const intervalId = setInterval(function(){
                console.log('indexesArray',indexesArray);
            }, 2000);
            return () => clearInterval(intervalId);
        }
        
    }, [indexesArray]);

    return indexesArray && JSON.stringify(indexesArray)
}

ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>

Upvotes: 1

Related Questions