ReactJS: setTimeout() not working?

JavascriptReactjs

Javascript Problem Overview


Having this code in mind:

var Component = React.createClass({

	getInitialState: function () {
		return {position: 0};	 
	},

	componentDidMount: function () {
		setTimeout(this.setState({position: 1}), 3000);
	},

	render: function () {
		 return (
		 	<div className="component">
		 		{this.state.position}
		 	</div>
		 ); 
	}

});

ReactDOM.render(
	<Component />,
	document.getElementById('main')
);

Isn't the state supposed to change only after 3 seconds? It's changing immediately.

My main goal here is to change the state every 3 seconds (with setInterval()), but since it was not working, I tried setTimeout(), which is not working either. Any lights on this? Thanks!

Javascript Solutions


Solution 1 - Javascript

Do

setTimeout(
    function() {
        this.setState({ position: 1 });
    }
    .bind(this),
    3000
);

Otherwise, you are passing the result of setState to setTimeout.

You can also use ES6 arrow functions to avoid the use of this keyword:

setTimeout(
  () => this.setState({ position: 1 }), 
  3000
);

Solution 2 - Javascript

setTimeout(() => {
  this.setState({ position: 1 });
}, 3000);

The above would also work because the ES6 arrow function does not change the context of this.

Solution 3 - Javascript

Anytime we create a timeout we should s clear it on componentWillUnmount, if it hasn't fired yet.

      let myVar;
         const Component = React.createClass({
        
            getInitialState: function () {
                return {position: 0};    
            },
        
            componentDidMount: function () {
                 myVar = setTimeout(()=> this.setState({position: 1}), 3000)
            },
        
            componentWillUnmount: () => {
              clearTimeout(myVar);
             };
            render: function () {
                 return (
                    <div className="component">
                        {this.state.position}
                    </div>
                 ); 
            }
        
        });

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);
   

Solution 4 - Javascript

I know this is a little old, but is important to notice that React recomends to clear the interval when the component unmounts: https://reactjs.org/docs/state-and-lifecycle.html

So I like to add this answer to this discussion:

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

Solution 5 - Javascript

setState is being invoked immediately due to the parenthesis! Wrap it in an anonymous function, then call it:

setTimeout(function() {
    this.setState({position: 1})
}.bind(this), 3000);

Solution 6 - Javascript

You didn't tell who called setTimeout

Here how you call timeout without calling additional functions.

1. You can do this without making additional functions.
setTimeout(this.setState.bind(this, {position:1}), 3000);

Uses function.prototype.bind()

setTimeout takes the location of the function and keeps it in the context.

2. Another way to do the same even by writing even less code.
setTimeout(this.setState, 3000, {position:1});

Probably uses the same bind method at some point

The setTimeout only takes the location of the function and the function already has the context? Anyway, it works!

NOTE: These work with any function you use in js.

Solution 7 - Javascript

Your code scope (this) will be your window object, not your react component, and that is why setTimeout(this.setState({position: 1}), 3000) will crash this way.

That comes from javascript not React, it is js closure


So, in order to bind your current react component scope, do this:

setTimeout(function(){this.setState({position: 1})}.bind(this), 3000);

Or if your browser supports es6 or your projs has support to compile es6 to es5, try arrow function as well, as arrow func is to fix 'this' issue:

setTimeout(()=>this.setState({position: 1}), 3000);

Solution 8 - Javascript

There's a 3 ways to access the scope inside of the 'setTimeout' function

First,

const self = this
setTimeout(function() {
  self.setState({position:1})
}, 3000)

Second is to use ES6 arrow function, cause arrow function didn't have itself scope(this)

setTimeout(()=> {
   this.setState({position:1})
}, 3000)

Third one is to bind the scope inside of the function

setTimeout(function(){
   this.setState({position:1})
}.bind(this), 3000)

Solution 9 - Javascript

You did syntax declaration error, use proper setTimeout declaration

message:() => { 
  setTimeout(() => {this.setState({opened:false})},3000); 
  return 'Thanks for your time, have a nice day 😊! 
}

Solution 10 - Javascript

Just pass the function as a reference, no need to wrap it in an anonymous function or even bind it, which creates yet another function.

setTimeout(this.setState, 500, {position: 1});

Enter setTimeout

It seems people don't realise that setTimeout and setInterval actually accept optional unlimited parameters.

setTimeout(callback, timeout?, param1?, param2?, ...)

The reason is to make calling the callback simpler, so instead of this

setTimeout(
  function(){
    this.doSomething(true, "string", someVariable)
  }.bind(this),
  500
)

You can write this

setTimeout(this.doSomething, 500, true, "string", someVariable)
Isn't that beautiful and elegant? 

Bug?

There is no bug in React calling setTimeout instantly, so if you were puzzled by it, consider this.

function doSomething() {/* */}

const a = doSomething() // immediately invokes and assigns a result
const b = doSomething   // stores a reference for later call

// call later
const x = a() // error
const y = b() // invokes doSomething and assigns a result

And in your case with setState, this is basically the same thing.
When you register your setTimeout callback, you mistakenly immediately call it, where instead you should pass a reference to it.

function doSomething() {/* */}

// wrong
setTimeout(doSomething(), 500) // This is basically the same as writing the `a` from above
setTimeout(a, 500)             // like this. See the problem? a() cannot be called later.

To fix it, you have three options.

  1. pass a reference
setTimeout(this.doSomething, 500)
  1. wrap in an anonymous arrow function which is transparent to this,
    meaning it captures the outer (parent) this.
    note that this wraps your function in another function every time you call this
setTimeout(() => this.doSomething(), 500)
  1. wrap in a standard anonymous function, but since it comes with it's own this, you must bind it to the this of the parent.
    note that this wraps your function in another function AND THEN binds it, which creates a third function every time
setTimeout(function(){this.doSomething()}.bind(this), 500)

Solution 11 - Javascript

Passing string literals Passing a string instead of a function to setTimeout() has the same problems as using eval().

componentDidMount: function () {
 // Do this instead
 setTimeout(function() {
 console.log('Hello World!');
 }, 500);
}

Using react hook

useEffect(() => {
  const timer = setTimeout(() => {
    console.log('This will run after 1 second!')
  }, 1000);
  return () => clearTimeout(timer);
}, []);

know more

Solution 12 - Javascript

Try to use ES6 syntax of set timeout. Normal javascript setTimeout() won't work in react js

setTimeout(
      () => this.setState({ position: 100 }), 
      5000
    );

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjbarradasView Question on Stackoverflow
Solution 1 - JavascriptDaniel A. WhiteView Answer on Stackoverflow
Solution 2 - JavascriptSteven ScaffidiView Answer on Stackoverflow
Solution 3 - JavascriptKhalid AzamView Answer on Stackoverflow
Solution 4 - JavascriptFernando LopesView Answer on Stackoverflow
Solution 5 - JavascripttymeJVView Answer on Stackoverflow
Solution 6 - JavascriptAdvisView Answer on Stackoverflow
Solution 7 - JavascriptXinView Answer on Stackoverflow
Solution 8 - JavascriptDarryl FabianView Answer on Stackoverflow
Solution 9 - JavascriptKARTHIKEYAN.AView Answer on Stackoverflow
Solution 10 - JavascriptQwertyView Answer on Stackoverflow
Solution 11 - JavascriptMD SHAYONView Answer on Stackoverflow
Solution 12 - JavascriptCodemakerView Answer on Stackoverflow