【问题标题】:Using setTimeout with React and Redux在 React 和 Redux 中使用 setTimeout
【发布时间】:2018-08-31 19:12:12
【问题描述】:

我有一些动画,我正试图使用​​ setTimeouts 开始工作,出于某种原因,它们会一遍又一遍地触发,直到时间结束。我有一个包含所有布尔值的减速器和一个切换它们的动作,但问题是无论 setTimeouts 中的条件是否为真,都会触发该动作。我查看了 chrome 控制台并确认这是真的,但我不知道为什么。我会把我的代码放在下面。

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指令移动到componentDidMount方法reactjs.org/docs/react-component.html#componentdidmount
  • @OlivierBoissé 是正确的,setTimeout 需要在componentDidMount() 方法中。组件不断地重新渲染,因此您在每次渲染时都执行新的 setTimeout。您还需要一种方法来阻止它。

标签: javascript reactjs redux settimeout


【解决方案1】:

setTimeout() 属于 componentDidMount 或 componentDidUpdate 方法。您还需要在 componentWillUnmount 方法中使用 clearTimeout 来取消超时,否则如果在超时触发之前卸载组件,您将收到 setState on an unmounted component 警告。这是一个简化的示例。

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() {...}

}

【讨论】:

  • 这是有道理的。我会尽快试一试。谢谢!
  • 请记住,如果您在 componentDidUpdate() 中执行 setTimeout,则需要检查以防止它多次触发,例如!this.enterAnimation &amp;&amp; this._startAnimation(timeout).
【解决方案2】:

我想更新我最终做了什么。我想补充一点,我正在使用 Flowtype 和 eslint 与 AirBnB 规则配对,所以我不得不稍微重构一下以满足它们。

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>
    );
  }
}

【讨论】:

    猜你喜欢
    • 2022-06-10
    • 2017-11-20
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2021-11-22
    相关资源
    最近更新 更多