简体   繁体   English

ES6 + React组件实例方法

[英]ES6 + React Component Instance Method

I'm making a small Video component in React (for you guessed it, playing videos) and I want to embed that component inside a parent component and then be able to call a play method on the video component. 我在React中制作了一个小Video组件(因为你猜对了,播放视频),我希望将该组件嵌入到父组件中,然后能够在视频组件上调用play方法。

My video component 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 component, lets call it Page : 现在,在父组件,让我们把它叫做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. 但是如果我记录.play它是未定义的。

Next I tried declaring play as a prop in Video and putting a default prop like: 接下来,我尝试在Video声明play作为道具并放置默认道具,如:

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

But in this context, this in undefined. 但在这种情况下, this是未定义的。

What is the proper way to expose a function on a React ES6 class so that it can be called by external components? 在React ES6类上公开函数以便外部组件可以调用它的正确方法是什么? Should I attach something to Video.prototype ? 我应该在Video.prototype一些东西吗?

The correct way to call an instance method of a child component 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 components 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 (eg event emitter) to manage the state. 做你想做的最好的方法是使用外部服务(例如事件发射器)来管理状态。 In Flux, these would be "stores". 在Flux中,这些将是“商店”。 The Video component would trigger actions based on its current state (eg PLAYBACK_STARTED ), which would in turn update the store. Video组件将根据其当前状态(例如PLAYBACK_STARTED )触发操作,这反过来会更新商店。 The Page component can fire a START_PLAYBACK action, which would also update the store. Page组件可以触发START_PLAYBACK操作,这也会更新商店。 Both components listen for changes in the store's state, and respond accordingly. 两个组件都会侦听商店状态的变化,并做出相应的响应。 Eg: 例如:

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

Flux is not a requirement here (eg you could use Redux or nothing at all). 此处不需要Flux(例如,您可以使用Redux或根本不使用Redux)。 What's important here is a clear, unidirectional data flow. 这里重要的是清晰的单向数据流。

You can use refs for passing a method from a child to its parent. 您可以使用refs将方法从子级传递给其父级。

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 公开组件功能

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM