我正在 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)
Flux 不是这里的要求(例如,您可以使用 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()} />
}
}
来自 公开组件函数