組合和繼承的概念時常讓大家混淆,都是獲得一樣的功能,為什麼又要分成兩種呢?這次將要帶大家用前端框架來看常見的組合與繼承。

先來看React官方的說法

React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components.

設計樣式的組合與繼承

雖然討論到設計樣式就會想到OOP,可是我們可以從OOP上的心得,將部分的精髓應用在前端上。
下面先來分別討論組合與繼承。

組合(Composite Design)

其實當你在組合V-DOM的Component的同時,你可能就已經使用過組合了,以下來看例子。
假設今天設計了一張GiftCard如下:

1
2
3
4
5
6
7
8
9
10
const GiftCard = () => {
return (
<div className="card-warp card-warp-primary">
<h2 className="title">Dear homie:</h2>
<p className="message">
Thank you for ur visiting!
</p>
</div>
);
}

但是你發現卡片的樣式可能會有好幾種樣式,以上面的例子是card-warp-primary
也許你的直覺會再寫一個相同結構的GiftCard在你的程式裡面,不過其實可以善用組合來設計。

1
2
3
4
5
6
7
8
9
10
const GiftCard = () => {
return (
<Content type="primary">
<h2 className="title">Dear homie:</h2>
<p className="message">
Thank you for ur visiting!
</p>
</Content>
);
}
1
2
3
4
5
6
7
8
const Content = (props) => {
const type = props.type;
return (
<div className={`card-warp card-warp-${type}`}>
{props.children}
</div>
);
}

這樣是不是就能達到樣式的組合性了?

然而其實,根據React官方的說法,其實是可自行定義名稱來使用的:

1
2
3
4
5
6
7
8
9
10
11
12
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
1
2
3
4
5
6
7
8
9
10
11
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}

不過其實這類的做法,其實就像是用JSX放V-DOM透過Attributes傳遞的概念。

那麼繼承呢?

我們一樣先來討論結論,根據React官方的說法:
At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.

意思是,官方找遍了各種方法使用繼承來運用在React,可是似乎沒有這麼必要刻意去使用繼承。
其實光是props搭配組合就很夠用在各種應用情境上了。

那麼繼承他所能帶來的特色又是什麼呢?

繼承的特色

相信寫過OOP的人都知道繼承的特色,就是子類別繼承父類別的東西,以下來分析優缺點。
優點:能夠無條件把父類別所有東西繼承下來(全部都是我的,真棒)
缺點:繼承無條件繼承了所有東西下來,這也意味著無法各自改變,只有子類別更動不會影響整體。

有發現嗎?繼承的優點同時也會是缺點,有時候繼承的很爽,但是會發現程式改起來可是會把你逼瘋的。
繼承同時也是高耦合的設計模式,所以輕易地使用容易讓程式整體變得難更動。
React官方大概也意識到組合的優點幾乎解決了大部分的問題,繼承已經並非那麼重要了
因此之後的走向都以Funtional based為主體發展下去了。