Redux 的 React 綁定庫包含了 容器組件和展示組件相分離 的開發思想。明智的做法是只在最頂層組件(如路由操作)里使用 Redux。其余內部組件僅僅是展示性的,所有數據都通過 props 傳入。
那么為什么需要容器組件和展示組件相分離呢?
這里有個基本原則:容器組件僅僅做數據提取,然后渲染對應的子組件,記住這個點,Trust me!
看下面這個展示列表的例子,不區分容器和展示組件的情況
// CommentList.js class CommentList extends React.Component { constructor() { super(); this.state = { comments: [] } } componentDidMount() { $.ajax({ url: "/my-comments.json", dataType: 'json', success: function(comments) { this.setState({comments: comments}); }.bind(this) }); } render() { return <ul> {this.state.comments.map(renderComment)} </ul>; } renderComment({body, author}) { return <li>{body}—{author}</li>; } }
-
可用性:CommentList不可以復用
-
數據結構:組件應該對所需要的數據有所預期,但這里其實沒有,PropTypes可以很好的做到這一點
那么來看下分離的情況:
// CommentListContainer.js class CommentListContainer extends React.Component { constructor() { super(); this.state = { comments: [] } } componentDidMount() { $.ajax({ url: "/my-comments.json", dataType: 'json', success: function(comments) { this.setState({comments: comments}); }.bind(this) }); } render() { return <CommentList comments={this.state.comments} />; } } // CommentList.js class CommentList extends React.Component { constructor(props) { super(props); } render() { return <ul> {this.props.comments.map(renderComment)} </ul>; } renderComment({body, author}) { return <li>{body}—{author}</li>; } }
這樣就做到了數據提取和渲染分離,CommentList可以復用,CommentList可以設置PropTypes判斷數據的可用性
來看下容器組件和展示組件的區別:
展示組件 | 容器組件 |
---|---|
關注事物的展示 | 關注事物如何工作 |
可能包含展示和容器組件,並且一般會有DOM標簽和css樣式 | 可能包含展示和容器組件,並且不會有DOM標簽和css樣式 |
常常允許通過this.props.children傳遞 | 提供數據和行為給容器組件或者展示組件 |
對第三方沒有任何依賴,比如store 或者 flux action | 調用flux action 並且提供他們的回調給展示組件 |
不要指定數據如何加載和變化 | 作為數據源,通常采用較高階的組件,而不是自己寫,比如React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create() |
僅通過屬性獲取數據和回調 | |
很少有自己的狀態,即使有,也是自己的UI狀態 | |
除非他們需要的自己的狀態,生命周期,或性能優化才會被寫為功能組件 |
優勢:
-
-
展示和容器更好的分離,更好的理解應用程序和UI
-
重用性高,展示組件可以用於多個不同的state數據源
-
展示組件就是你的調色板,可以把他們放到單獨的頁面,在不影響應用程序的情況下,讓設計師調整UI
-
迫使你分離標簽,達到更高的可用性
-