2017-01-04 3 views
3

https://github.com/selz/plyr 미디어 플레이어를 사용하는 React 구성 요소가 있습니다. 구성 요소가 마운트 해제 될 때까지 모든 것이 올바르게 작동하므로 Vimeo API에서 오류가 발생합니다. 구체적으로는 Uncaught (in promise) TypeError: Cannot read property 'postMessage' of null입니다.Vimeo API (ReactJS 및 Plyr 포함)

이 오류가 발생하면 this.player이 (가) undefined이므로 모듈을 다시로드하려고 시도하지만이를 파괴했다가 다시 시도하면로드됩니다. 아마 React Tree가 컴포넌트의 첫 번째 반복을 저장하고 있으며, 어떻게 든 그것을 완전히 파괴해야 할 필요가 있을까요?

import React, {Component, PropTypes} from 'react'; 
import {findDOMNode} from 'react-dom'; 
import plyr from 'plyr'; 

/** 
* @desc Regex to retrieve the Vimeo video ID from the URL. 
* @type {RegExp} 
*/ 
const regex = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/g; 

export default class Vimeo extends Component { 

    static propTypes = { 
    url: PropTypes.string.isRequired, 
    }; 

    constructor(props) { 
    super(props); 
    // Use regex to get the video id from the url 
    this.videoId = regex.exec(this.props.url); 
    } 

    /* 
    |-------------------------------------------------------------------------- 
    | Digest Cycle 
    |-------------------------------------------------------------------------- 
    */ 

    /** 
    * @desc Initiate video player. 
    */ 
    componentDidMount() { 
    this.player = plyr.setup(findDOMNode(this), { 
     controls: [], 
     autoplay: true, 
     loop: true, 
     mute: true, 
    }); 
    this.player[0].on('ready',() => { 
     // Mute the video 
     if (!this.player[0].isMuted()) { 
     this.player[0].toggleMute(); 
     } 
    }); 
    } 

    /** 
    * @desc Destroy video player 
    */ 
    componentWillUnmount() { 
    this.player[0].destroy(); 
    } 

    /* 
    |-------------------------------------------------------------------------- 
    | Render 
    |-------------------------------------------------------------------------- 
    */ 

    render() { 
    let player = null; 
    if (typeof this.videoId !== 'undefined' && this.videoId !== null) { 
     player = (
     <div> 
      <div 
      data-type="vimeo" 
      data-video-id={this.videoId} 
      /> 
     </div> 
    ); 
    } 

    return player; 
    } 
} 

답변

1

귀하의 문제가 Plyr 객체가 파괴 도착하는 방식으로 인해 발생되는 :

여기 내 구성 요소입니다. Plyr API에서 노출되는 방법 인 _destroy()을 살펴보십시오.

https://github.com/Selz/plyr/blob/master/src/js/plyr.js#L3234

당신이 볼 수 있듯이, 비 메오의 경우,이 라인 plyr.embed.unload().then(cleanUp);setTimeout에 다음 호출은 분명히 _destroy이 동기 호출 아니라고합니다. 먼저

, plyr.embed.unload()이에게 전화를하게하십시오 약속을 반환

https://github.com/vimeo/player.js/blob/e0f607196f7b38e3a9891e70dda38da2731cff79/src/player.js#L440

합니다. 일단 약속이 이행되면 Plyr의 cleanup 함수가 실행되고 DOM이 업데이트되고 변수가 재설정됩니다. 즉, Plyr 인스턴스가 완전히 기본값 또는 "파괴됨"으로 복원 될 때까지 기다리지 않고 구성 요소가 마운트 해제됩니다. 바로 구성 요소를 다시 마운트하면 예기치 않은 동작이 발생할 수 있습니다.

componentWillUnmount 내부에 destroy()을 사용하여 DOM을 업데이트하고 Plyr 인스턴스를 재설정하지 않는 것이 좋습니다. 대신 동영상 삽입을 감싸는 DOM 요소를 삭제하고 this.playernull으로 설정하면 내부의 Plyr 인스턴스가 누출되어 gc가 수집 할 수 있습니다. 다음에 컴포넌트가 마운트되면 비디오를 보유하고 있던 DOM 요소는 거기에 없을 것이며 플레이어는 새로운 Plyr 인스턴스를 설정하고 필요한 html을 다시 생성하여 정상적으로 초기화됩니다.

1

낮은 수준의 API 인 ReactTransitionGroup을 사용하여 새로운 라이프 사이클 componentWillLeave에 액세스 할 수 있습니다.

npm i -S react-addons-transition-group 

제공된 콜백을 호출하여 구성 요소를 마운트 해제하기 전에 플레이어가 삭제 될 때까지 기다릴 수 있습니다. 200ms의 제한 시간이면 충분하지만 안전하길 원한다면 늘릴 수 있습니다.

그래서 componentWillUnmount 제거하고

componentWillLeave(cb) { 
    this.player[0].destroy(); 
    setTimeout(cb, 200); 
} 

당신은 ReactTransitionGroupVimeo 구성 요소를 포장해야합니다,하지만 당신은 마음에 들지 않는 경우는 물론 래퍼를 만들 수 있습니다처럼 무언가에 의해 대체 취득 그것과 다른 곳에서 재사용 될 것입니다.


또한 react-plyr을 볼 수도 있습니다.그것은 당신과 같은 이슈를 가지고 있으며 아주 새로운 것이지만, 테스트와 멋진 구조를 가지고 있으며 더 많은 옵션을 지원합니다. 시간이 있으면 멋진 도서관으로 만들기위한 노력에 동참하는 것이 좋습니다.)

+0

@RyanPotter any updates? :) –