2016-01-07 3 views
3

Я делаю небольшой компонент Video в React (так как вы его догадались, воспроизводя видео), и я хочу встроить этот компонент в родительский компонент, а затем иметь возможность вызвать метод play на видео компонент.ES6 + React Component Instance Method

Мое видео компонент выглядит следующим образом:

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

По-моему, это был бы лучший способ. Это кажется немного громоздким (и для крошечного приложения, может быть), но когда ваше приложение масштабируется немного больше, оно будет намного чище. Например, возможно, вы позже захотите автоматически приостановить видео в ответ на несколько несвязанные действия пользователя (например, открытие меню).Вы можете передать метод через ref, но это грязно и неясно. Было бы лучше отправить действие - установить его и забыть. –

+0

Хммм интересно, мне нравится этот поток намного лучше. Затем компонент видео просто вызывает функции на своих реквизитах, которые определяются его родительскими компонентами, которые затем могут делать все, что они хотят, например, выполнять отправку. И было бы не сложно отправить действие только для воспроизведения определенного видео. Теоретически вы можете хранить источник видео как «currentVideosPlaying» в магазине redux, а затем сопоставлять их с подключенными компонентами. – 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