title | date | version |
---|---|---|
快速起步-组合与继承 |
2017-04-26 06:19:51 -0700 |
15.5.0 |
React
具有很强大的组合模型,我们推荐使用组合而不是继承来重用组件之间的代码。
在这一章节中,我们将思考一些React新手通常遇到的问题,并展示如何使用组合来解决它们。
一些组件并不能提前知道它们的子集。这在通用盒子组件,如 Sidebar
或者 Dialog
上尤其常见。
我们推荐这类组件使用特定的 children
属性,将子元素传递到其输出中:
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>
);
}
任何JSX标签 <FancyBorder>
内部的内容,都会作为 children
属性传递给 FancyBorder
组件。由于 FancyBorder
会在 <div>
中渲染 {props.children}
,传递的元素将会出现在最终输出中。
虽然这不太常见,但有时您可能需要在组件中设置多个“孔”(holes,译者注:插槽)。在这种情况下,您可以采用您自己的约定,而不是使用 children
:
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 />
} />
);
}
像 <Contacts />
和 <Chat />
这样的React元素只是对象,所以你可以像传递其他数据一样将其作为属性传递。
有时我们认为某些组件是其他组件的“特殊情况”。比如,我们认为 WelcomeDialog
是一个特殊的 Dialog
。
在React中,这也可以通过组合来实现,其中更“特殊”的组件会渲染更“通用”的组件,并且使用属性来配置通用组件:
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 React.Component {
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,包括原始值、React元素或函数。
如果你想在组件之中重用非UI的功能,我们建议您将其提取到单独的 JavaScript
模块中。组件可以导入它,并在不扩展它的情况下,使用哪些函数,对象或者是类。