2017-01-04 10 views
3

https://github.com/selz/plyrメディアプレーヤーを使用するReactコンポーネントがあります。コンポーネントがアンマウントするまではすべて正常に動作し、Vimeo APIからエラーが発生します。具体的には:Uncaught (in promise) TypeError: Cannot read property 'postMessage' of nullReactJSとPlyrを使用したVimeo API

このエラーが発生した後、私はthis.playerundefinedであるためにモジュールを再度ロードしようとしますが、それを破壊して再度実行するとロードされます。おそらく、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オブジェクトが破壊されますする方法によって引き起こされている:

は、ここに私のコンポーネントです。 _destroy()メソッドを見てください。これはPlyr APIで公開されているメソッドです。

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

あなたが見ることができるように、Vimeoの場合には、このラインplyr.embed.unload().then(cleanUp);setTimeoutへの次の呼び出しは、それを明確に_destroyは同期呼び出しではないことを確認します。

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

約束を返します。

まず、plyr.embed.unload()はこれを呼び出します。約束が満たされると、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を取り除く、あなたが好きではない場合は、ReactTransitionGroupにあなたのVimeoコンポーネントをラップする必要がありますが、あなたはもちろんのラッパーを作成することができます

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

のようなもので、それを交換ますそれは他の場所で再利用されます。


また、react-plyrを参照してください。それはあなたと同じ問題を抱えていて、全く新しいですが、テストや素敵な構造を持ち、より多くのオプションをサポートしています。あなたが時間があればそれをクールな図書館にする努力に参加することをお勧めします)

+0

@RyanPotter any updates? :) –

関連する問題