setInterval не очищается должным образом в React.js при работе с пакетом Reaction-YouTube - PullRequest
0 голосов
/ 23 января 2019

Я начинающий разработчик и пытаюсь разработать SPA в React, который использует YouTube API для извлечения данных.Используя эти данные, он отслеживает, смотрели ли пользователи видео.Я делаю это, вычисляя процент просмотра, используя некоторую простую математику, которая обновляется каждые пять секунд с помощью setInterval.Я делаю все это в сочетании с пакетом npm, называемым «Reaction-YouTube».

Внутри компонента у меня есть функция generatePercent (), которая захватывает данные события в соответствии с документацией реагировать на youtube и генерирует процент, это срабатывает, когда пользователь нажимает на воспроизведение видео.К сожалению, я не могу очистить этот интервал, когда пользователь нажимает паузу.Хуже того, кажется, что приложение генерирует несколько экземпляров setInterval.

Я пробовал все, от размещения этого в ComponentDidMount / ComponentWillUnmount до использования отслеживания состояния проигрывателя внутри состояния приложения ииспользуя операторы if / else, чтобы сказать, что фильм приостановлен, затем очистите интервал.Я просмотрел множество примеров на веб-сайте responsejs.org и других подобных проблемах на этом сайте, но ничего не помоглоЯ, наверное, просто не замечаю чего-то легкого, но я действительно в растерянности.Кажется, что многие проблемы связаны с тем, что мне нужно подключиться к event.target.property-of-the-вещь-i-want согласно документации youtube-реагировать, и это вызывает у меня несколько головных болейполучить его в противном случае.Любая помощь будет очень, очень признательна.

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.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Вам нужно хранить ваш интервал где-то за пределами функции generatePercent. Как только эта функция будет выполнена, все переменные, объявленные в этой функции, будут недоступны. При повторном запуске функции эта переменная getPercentage будет иметь значение null. Вы можете сохранить свой интервал в состоянии компонента следующим образом:

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 здесь .

0 голосов
/ 23 января 2019

Если вам нужен только один интервал, вы, вероятно, захотите установить его как свойство экземпляра для вашего компонента, а не помещать его в функцию в вашем методе рендеринга. Ваш метод рендеринга будет запускаться каждый раз, когда ваш компонент получает новый реквизит или обновляет свое состояние.

* 1003 например *

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

Я бы посоветовал сделать его свойством экземпляра, а не устанавливать его в ваше состояние, поскольку такие вещи, как правило, вызывают больше рендеров, чем необходимо.

Я бы, вероятно, предложил использовать ваши функции как методы класса. По сути, избегайте определения вещей внутри рендера, которые должны быть доступны при рендере.

например. смотрите здесь как определены методы handleFormSubmit и handleInputChange?

Надеюсь, это укажет вам правильное направление.

...