2016-01-07 69 views
3

我在React中製作了一個小的Video組件(因爲你猜對了,正在播放視頻),我想將該組件嵌入到父組件中,然後能夠調用play方法視頻組件。ES6 + React組件實例方法

我的視頻組件的樣子:

import React, { Component, PropTypes } from 'react'; 
import ReactDOM from 'react-dom'; 
const { string, func } = PropTypes; 

export default class Video extends Component { 

    static propTypes = { 
    source: string.isRequired, 
    type: string.isRequired, 
    className: string 
    }; 

    play =() => { 

    }; 

    render =() => { 
    const { className } = this.props; 
    return (
     <video className={ className } width="0" height="0" preload="metadata"> 
     <source src={ this.props.source } type={ this.type } /> 
     Your browser does not support the video tag. 
     </video> 
    ); 
    }; 
} 

它很簡單,沒有什麼特別的事情在這裏。

現在在父組件,讓我們把它叫做Page

export default class Page extends Component { 
    video = (
     <Video source="some_url" type="video/mp4" /> 
    ); 

    render =() => { 
     <div onClick={ this.video.play } /> 
    } 
} 

但是,如果我登錄.play這是不確定的。

接下來我想聲明play作爲道具在Video並把默認的道具,如:

static defaultProps = { 
    play:() => { 
     const node = ReactDOM.findDOMNode(this); 
    } 
} 

但在這種情況下,this不確定的。

在React ES6類上公開一個函數以便它可以被外部組件調用的正確方法是什麼?我應該附加一些東西到Video.prototype

回答

6

正確的方法來調用子組件的一個實例的方法是不能這樣做。 :-)

在這裏有很多資源討論爲什麼,但總結一下:它會創建一個不明確的數據流,它將組件連接在一起,這會減少問題的分離,並且測試更加困難。

要做你想做的事情的最好方法是使用外部服務(例如事件發射器)來管理狀態。在Flux中,這些將是「商店」。 Video組件將基於其當前狀態(例如PLAYBACK_STARTED)觸發動作,其將依次更新商店。 Page組件可以觸發START_PLAYBACK操作,該操作也會更新商店。這兩個組件都監聽商店狀態的變化,並做出相應的響應。例如:

Page -> START_PLAYBACK -> Video (play) -> PLAYBACK_STARTED -> Page (update ui) 

通量在這裏不是必需的(例如,您可以使用Redux或根本沒有)。這裏重要的是清晰的單向數據流。

+0

是的,我使用Redux和React-Redux來連接組件。因此,最好的方法是將容納視頻的容器組件連接到redux商店,當我想播放視頻時,只需發送一個動作即可。並暫停一個單獨的動作,等等。 – barndog

+0

在我看來,這將是最好的方法。這看起來有點麻煩(對於一個小應用程序,它可能會是這樣),但是當你的應用程序縮放得更大時,它會更乾淨。例如,也許您稍後想要自動暫停視頻以迴應與用戶行爲有些不相關的行爲(例如打開菜單)。你可以通過裁判傳遞方法,但這是混亂和不清楚。派遣一個行動會更好 - 設置它並忘記它。 –

+0

嗯有趣,我喜歡那個流動好多了。然後,視頻組件將只調用由它的父組件定義的道具上的功能,然後可以做他們想做的任何事情,例如執行派遣。並且僅派發一個動作來播放某個視頻並不難。您理論上可以將視頻源存儲在redux存儲中的「currentVideosPlaying」中,然後在連接的組件中對其進行匹配。 – barndog

3

您可以使用refs將方法從子項傳遞給其父項。

export default class Page extends Component { 
    video = (
     <Video source="some_url" ref="video" type="video/mp4" /> 
    ); 

    render =() => { 
     <div onClick={ this.refs.video.play } /> 
    } 
} 

Expose Component Functions

+0

嗯,這很有趣。所以我這樣做,當它是'onClick = {this.refs.video.play}'它崩潰了一些奇怪的原因,但是當我把'play'函數包裝在另一個函數中時,這一切都很好。 – barndog