7

I am trying to change the state of a component every 5 seconds as below inside componentDidMount() hook

import React, { Component } from 'react';

export default class ToTest extends Component {

  constructor(props) {
    super(props);
    this.state = {
      test: false
    };
  }

  componentDidMount() {
    setTimeout(() => { this.setState({ test: !this.state.test }) }, 5000);
  }

  renderDiv() {
    if(this.state.test) {
      return (<div>test is true</div>)
    }
    else {
      return (<div>test is false</div>)
    }
  }
  render() {
    return (
      <div>{ this.renderDiv() }</div>
    );
  }
}

But it executes only once. It changes from false to true once and then nothing. What am I missing?

troglodyte07
  • 3,598
  • 10
  • 42
  • 66

3 Answers3

13

componentDidMount() is only executed once when the component mounts and you only schedule it once. You have to use setInterval() to schedule it periodically.

Also when you update the state based on the current state you should use a callback in setState() that takes the previous state as react may batch multiple calls to setState().

And don't forget to cancel the timer in componentWillUnmount():

import React, { Component } from 'react';

export default class ToTest extends Component {
    state = {
        test: false,
    };

    componentDidMount() {
        this.timer = setInterval(
            () => this.setState(prevState => ({ test: !prevState.test })),
            5000,
        );
    }

    componentWillUnmount() {
        clearInterval(this.timer);
    }

    // other methods ...
}
trixn
  • 15,761
  • 2
  • 38
  • 55
  • This workes but the problem I am facing that it reRender again and again because of setState and componentWillUnmount never call – Sanaullah Oct 03 '19 at 09:45
  • @Sanaullah Then you call `setState` in the render method or in `componentDidUpdate` without a suitable condition. Likely every render you trigger a new update. `componentWillUnmount` is only called once when a component completely unmounts. It is not called after every re-render. – trixn Oct 03 '19 at 12:50
  • so how can I clearInterval – Sanaullah Oct 03 '19 at 13:10
  • @Sanaullah I don't know what you are trying to do so I can't answer that. Ask a new question with the relevant code and comment with the link. – trixn Oct 03 '19 at 13:22
4

Well setTimeout will only execute once, what you are looking for is setInterval:

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout

The setTimeout() method of the WindowOrWorkerGlobalScope mixin (and successor to window.setTimeout) sets a timer which executes a function or specified piece of code once after the timer expires.

Compare with

The setInterval() method of the WindowOrWorkerGlobalScope mixin repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.

Martin Schneider
  • 3,268
  • 4
  • 19
  • 29
2

As said in comments, you must use setInterval. the function setTimeout is called once. Make sure to clear the setInterval when the component unmounts. https://reactjs.org/docs/react-component.html#componentwillunmount

The code.

import React, { Component } from 'react';

export default class ToTest extends Component {

  constructor(props) {
    super(props);
    this.state = {
      test: false
    };
  }

  componentDidMount() {
    this.timer = setInterval(() => { this.setState({ test: !this.state.test }) }, 5000);
  }

  componentWillUnmount() {
    clearInterval(this.timer)
  }


  renderDiv() {
    if(this.state.test) {
      return (<div>test is true</div>)
    }
    else {
      return (<div>test is false</div>)
    }
  }
  render() {
    return (
      <div>{ this.renderDiv() }</div>
    );
  }
}
snowyBunny
  • 365
  • 4
  • 8
Damien
  • 287
  • 1
  • 9