简体   繁体   中英

Using setTimeout with React and Redux

I've got some animations that I'm trying to get to work using setTimeouts and for some reason they are firing over and over again until the end of time. I've got a reducer that holds all of my booleans and an action that toggles them, but the problem is that the action is being fired regardless of whether or not the condition is true in the setTimeouts. I've looked in the chrome console and confirmed this to be true, but I don't know why. I'll place my code below.

type LandingPagePropTypes = {
  displayCommandText: boolean,
  displayInstallText: boolean,
  displayAboutText: boolean,
  displayEnterText: boolean,
  displayWelcomeHeader: boolean,
  togglePropertyInState: (propertyName: string) => void,
  togglePopUpModal: (message: string) => void,
};

const LandingPage = (
  {
    displayWelcomeHeader,
    displayCommandText,
    displayAboutText,
    displayInstallText,
    displayEnterText,
    togglePropertyInState,
    togglePopUpModal,
  }: LandingPagePropTypes,
) => {
  setTimeout(() => {
    if (!displayCommandText) {
      togglePropertyInState('displayCommandText');
    }
  }, 1000);
  setTimeout(() => {
    if (!displayInstallText) {
      togglePropertyInState('displayInstallText');
    }
  }, 3000);
  setTimeout(() => {
    if (!displayAboutText) {
      togglePropertyInState('displayAboutText');
    }
  }, 4000);
  setTimeout(() => {
   if (!displayEnterText) {
      togglePropertyInState('displayEnterText');
    }
  }, 5000);
  setTimeout(() => {
    if (!displayWelcomeHeader) {
      togglePropertyInState('displayWelcomeHeader');
    }
  }, 1000);

  return (
    <div className="landing-page-container">
      <MediaQuery maxWidth={767}>
        <MobileLandingPage
          displayWelcomeHeader={displayWelcomeHeader}
        />
      </MediaQuery>

      <MediaQuery minWidth={768}>
        <DesktopLandingPage
          displayCommandText={displayCommandText}
          displayInstallText={displayInstallText}
          displayAboutText={displayAboutText}
          displayEnterText={displayEnterText}
          togglePopUpModal={togglePopUpModal}
        />
      </MediaQuery>
    </div>
  );
};

setTimeout() belongs in the componentDidMount or componentDidUpdate methods. You will also need a clearTimeout in the componentWillUnmount method to cancel the timeout or you'll get a setState on an unmounted component warning if you unmount the component before the timeout fires. Here's a simplified example.

class SomeComp extends Component {
  constructor() {...}

  _startAnimation = timeout => {
    this.enterAnimation = setTimeout(
      () => this.setState({ mode: 'entered' }),
      timeout
    )
  }

  componentDidMount() {
    const timeout = someNum

    this._startAnimation(timeout)
  }

  componentWillUnmount() {
    !!this.enterAnimation && clearTimeout(this.enterAnimation)
  }

  render() {...}

}

I wanted to update on what I ended up doing. I want to add that I'm using Flowtype and eslint paired with AirBnB rules so I had to restructure things a bit to satisfy both of them.

 class LandingPage extends Component <LandingPagePropTypes> { constructor(props: LandingPagePropTypes) { super(props); const { togglePropertyInState } = this.props; this.setCommandText = setTimeout(() => togglePropertyInState( 'displayCommandText' ), 1000); this.setInstallText = setTimeout(() => togglePropertyInState( 'displayInstallText' ), 3000); this.setAboutText = setTimeout(() => togglePropertyInState( 'displayAboutText' ), 4000); this.setEnterText = setTimeout(() => togglePropertyInState( 'displayEnterText' ), 5000); this.setWelcomeHeader = setTimeout(() => togglePropertyInState( 'displayWelcomeHeader' ), 1000); } componentWillUnmount() { const { displayCommandText, displayInstallText, displayAboutText, displayEnterText, displayWelcomeHeader, } = this.props; if (displayCommandText) { clearTimeout(this.setCommandText); } if (displayInstallText) { clearTimeout(this.setInstallText); } if (displayAboutText) { clearTimeout(this.setAboutText); } if (displayEnterText) { clearTimeout(this.setEnterText); } if (displayWelcomeHeader) { clearTimeout(this.setWelcomeHeader); } } setCommandText: TimeoutID; setInstallText: TimeoutID; setAboutText: TimeoutID; setEnterText: TimeoutID; setWelcomeHeader: TimeoutID; render() { const { displayWelcomeHeader, displayCommandText, displayAboutText, displayInstallText, displayEnterText, togglePopUpModal, } = this.props; return ( <div className="landing-page-container"> <MediaQuery maxWidth={767}> <MobileLandingPage displayWelcomeHeader={displayWelcomeHeader} /> </MediaQuery> <MediaQuery minWidth={768}> <DesktopLandingPage displayCommandText={displayCommandText} displayInstallText={displayInstallText} displayAboutText={displayAboutText} displayEnterText={displayEnterText} togglePopUpModal={togglePopUpModal} /> </MediaQuery> </div> ); } } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM