Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change a react state immediately by setTimeout after setState?

new in react here, don't know if it's right to do this on the setState callback like this?

           setTimeout(()=> {
            this.setState((state, props) => ({ activateLightColorForRed: true }), () => {
              setTimeout(()=> {
                this.setState(()=> ({ activateLightColorForRed: false }))
              }, 500);
              red.play();
            })
          }, toWait); 

or maybe something like this?

 this.setState((state, props) => {
    this.setState((state, props) => {
      activateLightColorForRed: true
    });
    setTimeout(() => { activateLightColorForRed: false },500)
  })

are the state on the setState callback updated? something weird is happening in my components, it's rendering multiple times. I am not sure but I think it's because I'm doing the first sample?

like image 447
gpbaculio Avatar asked Sep 11 '17 21:09

gpbaculio


People also ask

Does React re-render immediately after setState?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.

Why React setState setState does not update immediately?

State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately. The updater functions enqueue changes to the component state, but React may delay the changes, updating several components in a single pass.

Does setState happen immediately?

React hooks are now preferred for state management. Calling setState multiple times in one function can lead to unpredicted behavior read more.


1 Answers

Your question does not seem to follow the pattern of a regular react app. You should be using the lifecycle events to react to the state being changed. You should not be making multiple, nested, confusing callbacks (like it seems you want to do).

Might I suggest a structure more like this

class Foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activateLightColorForRed: false,
    };
  }
  componentDidUpdate(prevProps, prevState) {
    if (this.state.activateLightColorForRed) {
      // when the state is updated (turned red), 
      // a timeout is triggered to switch it back off
      this.turnOffRedTimeout = setTimeout(() => { 
        this.setState(() => ({activateLightColorForRed: false}))
      }, 500);
    }
  }
  componentWillUnmount() {
    // we set the timeout to this.turnOffRedTimeout so that we can
    // clean it up when the component is unmounted.
    // otherwise you could get your app trying to modify the state on an
    // unmounted component, which will throw an error
    clearTimeout(this.turnOffRedTimeout);
  }
  render () {
    // really simply ui to show how it *could* work
    return (
      <div onClick={this.turnLightRed}>
        The light is {this.state.activateLightColorForRed ? "Red" : "Green"}.
        <br /> Click to change!
      </div>
    )
  }
  turnLightRed = () => {
    // this function will turn the light red
    this.setState(() => ({ 
      activateLightColorForRed: true 
    }));
  }
}

ReactDOM.render(
  <Foo name="World" />,
  document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
<div id="container"></div>

Hope that helps.

like image 166
S.Kiers Avatar answered Oct 02 '22 14:10

S.Kiers