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>
);
}
在CodePen上试试吧。
在<FancyBorder>JSX标签里的任意内容作为children属性传递给FancyBorder组件。因为FancyBorder在一个<div>中渲染{props.children},被传入的元素会出现在最后的输出中。
有时在一个组件中你需要多个“洞”,这种情况相对少些。在这些情况下,代替使用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 />} />
);
}
在CodePen上试试。
React元素像<Contacts />和<Chat />仅是对象,你可以像任何其他数据一样将它们做为属性传递。
特殊化
有时我们认为组件是其他组件的特例。例如,我们可能会说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 spaceraft!" />
);
}
在CodePen上试试吧。
组合对被定义成类的组件一样有效:
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.handelSignUp.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}!');
}
}
在CodePen上试试吧。
在Facebook中,我们使用成千上万的组件,没有发现任何使用的例子是我们建议创建组件继承层次的。
Props and composition give you all the flexibility you need to customize a component`s look and behavior in an explicit and safe way.Remember that components may accept arbitrary props,including primitive values,React elements,or functions.
属性和组合给你以清晰安全的方式自定义组件样式和行为的所有灵活性。要记得组件接受任意的属性,包括原始的值,React元素或者方法。
如果你想在组件间复用没有UI的功能函数,我们建议提取它为单独的JavaScript模块。组件不扩展它,可以导入和使用这个函数、对象、或者类。