React 擁有一個強大的組合模型,我們建議使用組合而不是繼承以實現(xiàn)代碼的重用。
在本節(jié)中,我們將考慮幾個問題,即 React 新手經(jīng)常會使用繼承,并展示我們?nèi)绾瓮ㄟ^組合來解決它們。
包含
一些組件在設計前無法獲知自己要使用什么子組件,尤其在 Sidebar 和 Dialog 等通用 “容器” 中比較常見。
我們建議這種組件使用特別的 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>
);
}
在 <FancyBorder> JSX 標簽中的任何內(nèi)容被傳遞到 FancyBorder 組件中,作為一個 children prop(屬性)。由于 FancyBorder 渲染 {props.children} 到一個 <div> 中,傳遞的元素會呈現(xiàn)在最終的輸出中。
然而這并不常見,有時候,在一個組件中你可能需要多個 “占位符” 。在這種情況下,你可以使用自定義的 prop(屬性),而不是使用 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 元素本質(zhì)上也是對象,所以可以將其像其他數(shù)據(jù)一樣作為 props(屬性) 傳遞使用。
特例
有時候,我們考慮組件作為其它組件的“特殊情況”。例如,我們可能說一個 WelcomeDialog 是 Dialog 的一個特殊用例。
在React中,也可以使用組合來實現(xiàn),一個偏“特殊”的組件渲染出一個偏“通用”的組件,通過 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 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,我們還沒有發(fā)現(xiàn)任何用例,值得我們建議你用繼承層次結構來創(chuàng)建組件。
使用 props(屬性) 和 組合已經(jīng)足夠靈活來明確、安全的定制一個組件的外觀和行為。
切記,組件可以接受任意的 props(屬性) ,包括原始值、React 元素,或者函數(shù)。
如果要在組件之間重用非 UI 功能,我們建議將其提取到單獨的JavaScript 模塊中。組件可以導入它并使用該函數(shù),對象或類,而不擴展它。
參考: