danst_18
danst_18

Reputation: 497

Issue accessing state inside setInterval in React.js

I am trying to access the state of a component inside a setInterval in this way but it's not working:

componentDidMount: function() {
    setInterval(function() {
      console.log(this.state);
    }, 3000);
}

However, if I place the callback function in a separate component method, it works perfectly:

displayState: function() {
  console.log(this.state)
}
componentDidMount: function() {
    setInterval(this.displayState(), 3000);
}

Any idea why is this happening? I would prefer to use the first option.

Upvotes: 21

Views: 22027

Answers (3)

CodingYourLife
CodingYourLife

Reputation: 8626

For the functional syntax this should do the trick of accessing props and state inside an interval function:

useEffect(() => {
    //run instantly
    functionThatShouldRunEveryTenSeconds(props);

    const interval = setInterval(() => {
        //every 10 seconds
        functionThatShouldRunEveryTenSeconds(props);
    }, 1000);
    return () => clearInterval(interval);
}, []);

You should be able to access everything like state and props as normal.

Upvotes: 1

Tom Fenech
Tom Fenech

Reputation: 74705

In your first example, this is out of scope when the callback function fires. One way to solve this problem would be to use a variable:

componentDidMount: function() {
    var self = this;
    setInterval(function() {
      console.log(self.state);
    }, 3000);
}

The problem with your second attempt is that you are calling the function immediately and passing the result of executing the function to setInterval. You should pass the function itself, taking care to bind the value of this:

componentDidMount: function() {
    setInterval(this.displayState.bind(this), 3000);
}

To clarify, the difference between this approach and the second example in your question is that here, a function is being passed to setInterval (because function.bind() returns a function).

As you are using React.createClass, it is not necessary to manage the binding of this yourself, due to autobind. This means that you can just pass the function itself and this will be the same as in the original context:

componentDidMount: function() {
    setInterval(this.displayState, 3000);
}

Of course, the most suitable approach depends on whether you prefer to use an anonymous function or not.

Upvotes: 38

David Hellsing
David Hellsing

Reputation: 108530

You need to execute the interval handler with the correct reference to this. Use React’s autobinding for the cleasest solution IMO:

displayState: function() {
  console.log(this.state)
},
componentDidMount: function() {
    setInterval(this.displayState, 3000)
}

Or use bind if you want an anonymous function:

componentDidMount: function() {
    setInterval(function() {
        console.log(this.state)
    }.bind(this), 3000)
}

Upvotes: 5

Related Questions