反应:问题传递状态到setInterval

时间:2019-12-15 13:28:50

标签: reactjs state settimeout setinterval setstate

  • 我正在尝试创建一个简单的应用程序,以播放嵌入在iFrame中的Youtube视频。
    • 一个视频结束时,下一个视频开始
    • 某些视频只能播放特定的时长(可以使用Youtube URL中的开始和结束参数来设置,例如https://www.youtube.com/embed/iK2eOiSh6HI ?&start = 22&end = 28

我正在尝试在函数(setInterval)中使用playNextVideo在开始时间和结束时间之间的持续时间之后播放下一个视频。为此,我要解析URL,并从开始时间中减去结束时间。

this.setState({
        timer: (parseInt(parsedUrl.end, 10) - parseInt(parsedUrl.start, 10)) * 1000
      });

例如,如果结束是28秒,而开始是22秒,则结果是6秒。

然后我将this.state.timer作为间隔时间传递到setInterval中,但是,不是像预期的那样在playNextVideo中指定的持续时间内调用setInterval在看似随机的时间被召回。


这是完整的代码:

class App extends Component {

  state = {
    timer: 8000,
    urlList: {
      _01_3DAnimations: "https://www.youtube.com/embed/iK2eOiSh6HI?&start=22&end=28",
      _02_theRoom_hiDoggy: "https://www.youtube.com/embed/QgXYd6k251Q?&start=0&end=30 ",
      _03_flyingLotus_zodiacShit: "https://www.youtube.com/embed/0ScYz9sNaQk?&start=0&end=92"
    },
    activeUrl: "https://www.youtube.com/embed/Z1OLG7F3HD4?&start=22&end=28"

  }

  playNextVideo() {

    const keys = Object.keys(this.state.urlList);
    let parsedUrl = queryString.parse(encodeURI(this.state.activeUrl));

    setInterval(() => {
      const randomUrl = this.state.urlList[keys[keys.length * Math.random() << 0]];

      parsedUrl = queryString.parse(encodeURI(randomUrl));

      this.setState({
        timer: (parseInt(parsedUrl.end, 10) - parseInt(parsedUrl.start, 10)) * 1000
      });

      console.log("timer: ", this.state.timer);

      this.setState({
        activeUrl: randomUrl
      });

    }, this.state.timer);
  }

  componentDidMount() {
    this.playNextVideo();
  }

2 个答案:

答案 0 :(得分:0)

您应该创建另一种更新状态的方法

  timer () {
      const randomUrl = this.state.urlList[keys[keys.length * Math.random() << 0]];

      parsedUrl = queryString.parse(encodeURI(randomUrl));

      this.setState({
        timer: (parseInt(parsedUrl.end, 10) - parseInt(parsedUrl.start, 10)) * 1000
      });

      console.log("timer: ", this.state.timer);

      this.setState({
        activeUrl: randomUrl
      });
  };


  playNextVideo() {
    const keys = Object.keys(this.state.urlList);
    let parsedUrl = queryString.parse(encodeURI(this.state.activeUrl));

    setInterval( timer, this.state.timer);
  }

答案 1 :(得分:0)

我会重新考虑您的方法,因为此处setInterval()的概念存在一些问题:

  • 需要恒定的延迟时间
  • 由于未清除它,因此多次调用将导致该函数在每个时间间隔重复执行

我建议使用setTimeout(),因为它只会在超时后导致一个呼叫。

请注意,您仍然需要解决用户在暂停之前何时暂停视频的问题:

function App({ urlList }) {
  const [activeUrl, setActiveUrl] = useState(urlList[0]);

  React.useEffect(() => {
    const { start, end } = queryString.parse(encodeURI(activeUrl));
    const delay = parseInt(end, 10) - parseInt(start, 10) * 1000;

    const timeout = setTimeout(() => {
      const urls = urlList.filter(url => url !== activeUrl);
      const index = Math.floor(urls.length * Math.random());

      setActiveUrl(urls[index]);
    }, delay);

    // this will be called if the component unloads before the timeout
    return () => {
      clearTimeout(timeout);
    };
  }, [urlList, activeUrl, setActiveUrl]);

  ...
}

然后使用如下组件:

<App urlList={[
  "https://www.youtube.com/embed/Z1OLG7F3HD4?&start=22&end=28",
  "https://www.youtube.com/embed/iK2eOiSh6HI?&start=22&end=28",
  "https://www.youtube.com/embed/QgXYd6k251Q?&start=0&end=30",
  "https://www.youtube.com/embed/0ScYz9sNaQk?&start=0&end=92"
]}/>