React具有强大的组合模型,我们推荐使用组合来代替继承,这样可以在组件间重用代码。
在本节中,我们将考虑几个问题,遇到这些问题时,刚接触React的开发者一般会考虑使用继承,而我们将展示如何用组合来解决他们。
包含
一些组件提前不知道它的孩子。在诸如侧栏和对话框这些通用“框”中尤为常见。
我们建议这种组件使用专门的children
prop来直接传递子元素到他们的输出:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
这使得其他组件可以通过嵌套JSX传递任意子元素给他们:
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
特殊化
有时你我们认为一些组件是其他组件的“特殊情况”。比如,我们说WelcomeDialog
是Dialog
的特例。
在React中,这也可以通过组合来完成:通过props配置一个相对“通用的”组件,来渲染出一个相对“特殊的”组件:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children}
</FancyBorder>
);
}
class SignUpDialog extends {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login}
onChange={this.handleChange} />
<button onClick={this.handleSignUp}>
Sign Me Up!
</button>
</Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
那继承咋样?
在Facebook,我们在数千个组件中使用React,尚未发现有什么组件,需要我们推荐你使用继承去实现。
Props和组合提供了足够的灵活度,使得你能够以明确且安全的方法来自定义组件的外观和行为。
如果你想在组件间复用非界面功能,我们建议将它抽取到单独的JavaScript模块。组件可以导入它,然后使用需要的函数,对象或类,而不必扩展(继承)它。