React.js: Container vs Presentational Components
14 Apr 2018實作元件時,決定要做成 Container Components 或 Presentational Components 的主要因素是 是否需要存取資料。
Container Components
- 又稱 Smart Components。
- 著重在怎麼完成工作。例如:資料的取得和儲存、包裝其子元件。
- 擁有內部狀態(State),以提供自身或其他元件所需的資料。
- 存取資料
- 從 Store 取得資料後,使用 props 提供自身或其子元件所需資料。
- 發送 Action 和提供 Callback 來與 Store 溝通,Action 會將 API 的結果回傳至 Container 更新元件自身狀態或送到 Reducer 更新 Store。
- 擁有 Lifecycle Hooks。
- 與 React-Redux 綁定來產生這個 Container 以管理整個 App 的狀態。
範例
這個元件 Article 是用來檢視一篇文章,並可刪除這篇文章。
class Article extends Component {
constructor(props) {
super(props);
this.state = { status: 'active' }; // 擁有內部狀態
}
componentDidMount() {
// 擁有 Lifecycle Hooks
const { id } = this.props.match.params;
this.props.fetchPost(id); // 發送 Action
}
onDeleteClick() {
const { id } = this.props.match.params;
this.setState({ status: 'deleting' });
this.props.deletePost(id, () => {
// 發送 Action
this.props.history.push('/'); // 提供 Callback
this.setState({ status: 'deleted' });
});
}
// 提供資料、包裝子元件
render() {
return (
<div>
<button onClick={this.onDeleteClick.bind(this)}>Delete Post</button>
<ArticleDetail post={this.props.post} />
</div>
);
}
}
Presentational Components
- 又稱 Dumb Components。
- 著重在畫面的呈現。例如:DOM Markup、CSS Style。
- 從 props 取得所需資料和 Callback,與 Action 和 Store 等資料互動無關。
- 沒有內部狀態,通常是 Functional / Pure / Stateless Components。
範例
這個元件 ArticleDetail 從父層 props 得到 post,接著輸出一段 HTML,內含剛剛從 post 內得到的標題、分類和內容。
const ArticleDetail = ({ post }) => {
return (
<div>
<h3>{post.title}</h3>
<h6>Categories: {post.categories}</h6>
<p>{post.content}</p>
</div>
);
};
區分為 Container 和 Presentational Components 的優點
- 關注點分離。將 UI 與資料的處理分開。
- 提高重複使用性。例如:可搭配不同的資料來源卻呈現相同的畫面。
建立元件時首選 Presentational Components,之後若有其他需求再重構成 Container Components 即可,這樣會比較簡單乾淨。