最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ES6 + React Component Instance Method - Stack Overflow

programmeradmin0浏览0评论

I'm making a small Video ponent in React (for you guessed it, playing videos) and I want to embed that ponent inside a parent ponent and then be able to call a play method on the video ponent.

My video ponent looks like:

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>
    );
  };
}

It's really simple, nothing fancy going on here.

Now in the parent ponent, lets call it Page:

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

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

However if I log .play it's undefined.

Next I tried declaring play as a prop in Video and putting a default prop like:

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

But in this context, this in undefined.

What is the proper way to expose a function on a React ES6 class so that it can be called by external ponents? Should I attach something to Video.prototype?

I'm making a small Video ponent in React (for you guessed it, playing videos) and I want to embed that ponent inside a parent ponent and then be able to call a play method on the video ponent.

My video ponent looks like:

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>
    );
  };
}

It's really simple, nothing fancy going on here.

Now in the parent ponent, lets call it Page:

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

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

However if I log .play it's undefined.

Next I tried declaring play as a prop in Video and putting a default prop like:

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

But in this context, this in undefined.

What is the proper way to expose a function on a React ES6 class so that it can be called by external ponents? Should I attach something to Video.prototype?

Share Improve this question asked Jan 7, 2016 at 21:04 barndogbarndog 7,1839 gold badges56 silver badges108 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 6

The correct way to call an instance method of a child ponent is to not do it. :-)

There are many resources here that talk about why, but to summarize: it creates an unclear data flow, it couples ponents together which decreases separation of concerns, and it is harder to test.

The best way to do what you want is to use an external service (e.g. event emitter) to manage the state. In Flux, these would be "stores". The Video ponent would trigger actions based on its current state (e.g. PLAYBACK_STARTED), which would in turn update the store. The Page ponent can fire a START_PLAYBACK action, which would also update the store. Both ponents listen for changes in the store's state, and respond accordingly. E.g.:

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

Flux is not a requirement here (e.g. you could use Redux or nothing at all). What's important here is a clear, unidirectional data flow.

You can use refs for passing a method from a child to its parent.

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

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

From Expose Component Functions

发布评论

评论列表(0)

  1. 暂无评论