對我的程式碼有最深遠影響的一個React模式叫 container component 模式。
Jason Bonta 講了如何建立高效能元件(High Performance Components),這個演講講的就是 container components。
這個概念非常簡單:
一個 container 僅僅只是做資料拉取然後渲染它對應的子元件。
“Corresponding” 意味著分享同一個名稱的元件,例如:
(StockWidgetContainer) => StockWidget;
(TagCloudContainer) => TagCloud;
(PartyPooperListContainer) => PartyPooperList;
複製程式碼
這就是其中的概念。
Why containers?
假設你有一個用於展示評論的元件。在你不使用 container 元件的時候,你會把所有程式碼都放在一個地方:
class CommentList extends React.Component {
this.state = { comments: [] };
componentDidMount() {
fetchSomeComments(comments =>
this.setState({ comments: comments }));
}
render() {
return (
<ul>
{this.state.comments.map(c => (
<li>{c.body}—{c.author}</li>
))}
</ul>
);
}
}
複製程式碼
你的元件就是用於拉取資料並展示它。這並沒有什麼錯,但是你錯過了一些 React 的優點。
可複用性 (Reusability)
除非在完全相同的情況下,否則CommentList
元件無法被複用。
資料結構(Data structure)
你的標記元件應該給出他們所期望的資料型別。PropTypes
就是做這個的。
我們的元件對資料結構要求很高但是沒有辦法說出這些要求。如果 json 的介面資料改變了,這個元件會不做出任何提示出錯。(其實想說的就是,無法好好利用 PropTypes 來把控資料結構是否正確)
用container重寫一遍 (Once again. This time with a container)
首先,我們把資料拉取的功能放到 container 元件上。
class CommentListContainer extends React.Component {
state = {
comments: []
};
componentDidMount() {
fetchSomeComments((comments) => this.setState({ comments: comments }));
}
render() {
return <CommentList comments={this.state.comments} />;
}
}
複製程式碼
現在,我們修改CommentList
讓它接收comments
作為prop
。
const CommentList = (props) => (
<ul>
{props.comments.map((c) => (
<li>
{c.body}—{c.author}
</li>
))}
</ul>
);
複製程式碼
我們學到了啥?(So, what did we get?)
我們實際上得到了很多...
我們分離了資料拉取和渲染(data-fetching and rendering)。
我們使我們的 CommentList
元件得以複用。
我們賦予了CommentList
設定PropTypes
和錯誤提示的能力。
我是一個container components
的大粉絲。他們讓我的 React game 有了很大的進步,並且使我的元件更加易讀。試試,看看 Jason 的演講。太棒了!
Carry on, nerds.
——完——