ES6+React组件实例方法

ES6 + React Component Instance Method

本文关键字:实例方法 组件 ES6+React      更新时间:2023-09-26

我正在React中制作一个小的Video组件(你猜对了,播放视频),我想将该组件嵌入父组件中,然后能够在视频组件上调用play方法。

我的视频组件看起来像:

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上附加一些东西吗?

调用子组件的实例方法的正确方法是不调用。:-)

这里有很多资源可以讨论原因,但要总结一下:它创建了一个不清晰的数据流,它将组件耦合在一起,从而减少了关注点的分离,而且更难测试。

执行所需操作的最佳方法是使用外部服务(例如事件发射器)来管理状态。在Flux中,这些将是"商店"。Video组件将基于其当前状态触发动作(例如PLAYBACK_STARTED),这将反过来更新存储。Page组件可以触发START_PLAYBACK操作,该操作也将更新存储。这两个组件都会侦听商店状态的更改,并做出相应的响应。例如:

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

通量在这里不是一个要求(例如,你可以使用Redux或什么都不使用)。这里重要的是一个清晰、单向的数据流。

您可以使用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