React具有强大的组合模型,我们建议使用组合而不是继承来复用组件之间的代码。
本章节中,将围绕几个React新手经常使用继承来解决的方案,展示怎么使用组合来解决。
1.包含关系
一些组件不能提前知道它们的子组件是什么,这对于Sidebar
或Dialog
这类通用容器尤其常见。
我们建议这些组件使用children
属性,将子元素直接传递输出。
<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 Contacts(){
return(
<div className="Contacts">hahahaha</div>
)
}
function Chat(){
return(
<div className="Chat">hehehehe</div>
)
}
function App(){
return(
<SplitPane left={<Contacts />} right={<Chat />} />
)
}
ReactDOM.render(
<App />,document.getElementById('root')
)
2.特殊实例
有时候我们认为组件是其他组件的特殊实例,比如我们会说WelcomeDiolag
是Diolag
的特殊实例。
在React中,这也是通过组件在实现的。
通过配置属性,用比较特殊的组件,来渲染比较通用的组件。
function FancyBorder(props){
return(
<div className={'FancyBorder FancyBorder-'+props.color}>
{props.children}
</div>
)
}
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" />
)
}
ReactDOM.render(
<WelcomeDialog />,document.getElementById('root')
)
组合对定义为类的组件同样适用:
function FancyBorder(props){
return(
<div className={'FancyBorder FancyBorder-'+props.color}>
{props.children}
</div>
)
}
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 type="text" 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,s${this.state.login}!`)
}
}
ReactDOM.render(
<SignUpDialog />,document.getElementById('root')
)
3.继承
在 Facebook 网站上,我们的 React 使用了数以千计的组件,然而却还未发现任何需要推荐你使用继承的情况。
属性和组合为你提供了以清晰和安全的方式自定义组件的样式和行为所需的所有灵活性。请记住,组件可以接受任意元素,包括基本数据类型、React 元素或函数。
如果要在组件之间复用 UI 无关的功能,我们建议将其提取到单独的 JavaScript 模块中。这样可以在不对组件进行扩展的前提下导入并使用该函数、对象或类。
网友评论