React有十分强大的组合模式,我们推荐组合而非继承来实现组件之间的代码重用
包含关系
有些组件无法提前知道他们子组件的具体内容,在SlideBar(侧边栏)和Dialog(对话框)等展现通用容器的特别容易遇到这样的情况
我们建议这些组件使用children prop
来将他们的子组件渲染到结果中
props.children
把所有子组件显示出来
示例
import React ,{Component} from 'react'
import './combanation.css'
function FancyBorder (props) {
return(
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
)
}
function WelcomeDialog () {
return (
<FancyBorder color='blue'>
<h1 className='Dialog-title'>Welcome</h1>
<p className='Dialog-message'>Thank you visition our spacecraft</p>
</FancyBorder>
)
}
export default WelcomeDialog
上面代码中,通过props.children,我们可以把FancyBorder
里面的所有内容作为参数传递给FancyBorder组件,因为FancyBorder
将{props.children}
渲染在一个div
中,被传递的这些纸组件最终都会出现在输出结果中
少数情况下,你可能需要在一个组件中预留几个'洞',这种情况下,我们可以不适用children
,而是自行约定:将所有内容传入props,并使用相应的prop
示例
function SplitPane (props) {
return(
<div className='SplitPane'>
<div className='SplitPane-left'>{props.left}</div>
<div className='SplitPane-right'>{props.right}</div>
</div>
)
}
function Contacts(){
return(
<ul>
<li>微信</li>
<li>电话</li>
<li>QQ</li>
</ul>
)
}
function Chat(){
return(
<div>请和我联系</div>
)
}
function Bar(){
return (
<SplitPane left={<Contacts />} right={<Chat />}></SplitPane>
)
}
export default Bar
<Contacts />
和<Chat />
之类的React元素本质就是对象,所以可以把它们当做props,像其他数据一样传递,这种方法可能使你想到其他库的槽(slot)的概念,但在react中没有
特例关系
有些时候,我们会把一些组件看成是其他组件的特殊实例,比如WelcomeDialog
是Dialog
的特殊实例
在React中,我们也可以通过组合来实现这一点,"特殊"组件可以通过props定制并渲染一般组件
function Dialog (props) {
return(
<FancyBorder color='blue'>
<h1>{props.title}</h1>
<p>{props.message}</p>
</FancyBorder>
)
}
function WelcomeDialog(){
return(
<Dialog title='Welcome' message='Thank you for visiting our spacecraft'></Dialog>
)
}
组合也同样适用于class形式定义的组件
示例
function Dialog (props) {
return(
<FancyBorder color='blue'>
<h1>{props.title}</h1>
<p>{props.message}</p>
{props.children}
</FancyBorder>
)
}
class SigUpDialog extends React.Component{
constructor (props) {
super(props);
console.log(this)
this.state = {
login:''
}
}
render () {
return(
<Dialog title='Mars Exploration Program' message='How should we refer to you'>
<input type="text" value={this.state.login} onChange={this.handleChange.bind(this)} />
<button onClick={this.handleSignUp.bind(this)}>sign me up</button>
</Dialog>
)
}
handleChange(e){
this.setState({
login:e.target.value
})
}
handleSignUp(){
alert(`Welcome aboard,${this.state.login}!`)
}
}
export default SigUpDialog
那么继承呢?
在Facebook,成百上千个组件中适用react,并没有发现需要使用继承来构建组件层次的情况
props和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。