【问题标题】:setInterval not clearing properly in React.js when dealing with react-youtube package处理 react-youtube 包时,在 React.js 中 setInterval 未正确清除
【发布时间】:2019-06-16 11:14:23
【问题描述】:

我是一名初出茅庐的开发人员,我正在尝试在 React 中设计一个使用 YouTube API 检索数据的 SPA。它使用该数据跟踪用户是否观看过视频。我通过使用一些简单的数学计算观看百分比来做到这一点,该数学每五秒使用 setInterval 更新一次。我正在结合一个名为“react-youtube”的 npm 包来完成这一切。

在组件内部,我有一个名为 generatePercent() 的函数,它根据 react-youtube 文档获取事件数据并生成百分比,当用户点击视频播放时触发。不幸的是,当用户点击暂停时,我无法清除此间隔。更糟糕的是,该应用似乎还生成了多个 setInterval 实例。

我已经尝试了所有方法,从将其放置在 ComponentDidMount/ComponentWillUnmount 中,到使用在应用程序状态中跟踪播放器的状态,以及使用 if/else 语句说电影已暂停然后清除间隔。我查看了有关 reactjs.org 的大量示例以及该站点上的其他类似问题,但没有任何效果。我可能只是没有注意到一些简单的事情,但我真的很茫然。很多问题似乎源于我必须根据 youtube-react 文档利用 event.target.property-of-the-thing-i-want 的事实,这让我有些头疼否则检索它。任何帮助将非常非常感激。

import React, { Component } from 'react'
import YouTube from 'react-youtube'

class Player extends Component {
render() {
    // setIsPlaying is code that sets the state this.state.isPlaying   in App.js 
    // this.state.isPlaying is passed down from state as props into this component
    const { currentMovie, setIsPlaying, isPlaying } = this.props

    const opts = {
        height: '500px',
        width: '100%',
        playerVars: {
            autoplay: 0,
            controls: 0
        }
    }

    const setState = (event) => {
        const playerState = event.target.getPlayerState()
        setIsPlaying(playerState)
    }

    const generatePercent = (event) => {
        const getPercentage = setInterval(() => {
            const position = event.target.getCurrentTime()
            const duration = event.target.getDuration()
            const percent = Math.round((position / duration) * 100) + '%'
            console.log(percent)
        }, 5000)

        if (isPlaying === 1) {
            return getPercentage
        } else {
            clearInterval(getPercentage)
        }
    }

    return (
        <YouTube
            videoId={currentMovie}
            opts={opts}
            onReady={setState}
            onStateChange={setState}
            onPlay={generatePercent}
            onPause={generatePercent}
        />
    )
}
};

export default Player;

我只希望 setInterval 在用户点击播放时生成百分比,并在用户点击暂停时暂停生成。现在 setInterval 不会暂停,它会创建多个 setInterval 实例。

【问题讨论】:

    标签: reactjs setinterval


    【解决方案1】:

    如果您只想要一个间隔,您可能希望将其设置为组件上的实例属性,而不是将其放入渲染方法中的函数中。每当您的组件获得新的道具或更新其状态时,您的渲染方法都会运行。

    例如

    class Player extends Component {
      interval = null;
      render() {
      // reuse and clear the same interval as this.interval here
      }
    }
    

    我建议将其设为实例属性,而不是将其设置为您的状态,因为这类事情往往会导致不必要的渲染。

    我可能建议也将您的函数作为类方法。基本上避免在渲染内部定义比跨渲染可用的东西。

    例如请参阅here handleFormSubmithandleInputChange 方法是如何定义的?

    希望这会为您指明正确的方向。

    【讨论】:

    • 谢谢!我会试试看。我仍在学习细节,所以我忘记了这些事情。感谢您的时间。
    【解决方案2】:

    您需要将区间存储在 generatePercent 函数之外的某个位置。一旦该函数运行完毕,该函数中声明的所有变量都将无法访问。当您第二次运行该函数时,该 getPercentage 变量将为空。 您可以像这样将间隔存储在组件状态中:

    constructor() {
       super();
       this.state = {
          myInterval: null,
       };
    }
    

    您的 generatePercent 函数可能如下所示:

    generatePercent() {
      // Fetch the interval from the state
      let { myInterval, isPlaying } = this.state;
    
      if (!isPlaying) {
        // If the video has stopped, clear the interval
        clearInterval(myInterval);
        // Delete the reference or the (!myInterval) check below will still return false
        myInterval = null;
      } else if(!myInterval) {
        // Create an interval
        myInterval = setInterval(() => this.handleInterval(), 1000);
      }
    
      // Save the interval into the component state
      this.setState({myInterval});
    }
    

    使用有效的 JSFiddle here

    【讨论】:

    • 这很有帮助。我不认为将间隔设置为状态的一部分。过几次我会试试的。非常感谢您的帮助!
    猜你喜欢
    • 2021-10-27
    • 2015-05-26
    • 2011-05-08
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2018-01-22
    • 1970-01-01
    相关资源
    最近更新 更多