詳解展現組件和容器組件的區別和應用

在使用React中,你是否會出現過一個文件的代碼不少,既存在應用數據的讀取和處理,又存在數據的顯示,並且每一個組件還不能複用。html

首先咱們來看一個容器組件和展現組件一塊兒的例子吧。react

class TodoList extends React.Component{
    constructor(props){
        super(props);
        this.state ={
            todos:[]
        }
        this.fetchData = this.fetchData.bind(this);
    }
    componentDidMount(){
        this.fetchData();
    }
    fetchData(){
        fetch('/api/todos').then(data =>{
            this.setState({
                todos:data
            })
        })
    }
    render(){
        const {todos} = this.state;
        return (<div>
                <ul>
                    {todos.map((item,index)=>{
                        return <li key={item.id}>{item.name}</li>
                    })}
                </ul>
            </div>)
    }
}
複製代碼

你們能夠看到這個例子是沒有辦法複用的,由於數據的請求和數據的展現都在一個組件進行,要實現組件的複用,咱們就須要將展現組件和容器組件分離出來。api

具體代碼以下:數組

//展現組件
class TodoList extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        const {todos} = this.props;
        return (<div>
                <ul>
                    {todos.map((item,index)=>{
                        return <li key={item.id}>{item.name}</li>
                    })}
                </ul>
            </div>)
    }

//容器組件
class TodoListContainer extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            todos:[]
        }
        this.fetchData = this.fetchData.bind(this);
    }
    componentDidMount(){
        this.fetchData();
    }
    fetchData(){
        fetch('/api/todos').then(data =>{
            this.setState({
                todos:data
            })
        })
    }
    render(){
        return (<div>
                <TodoList todos={this.state.todos} />    
            </div>)
    }
}

複製代碼

當咱們把組件分離成容器組件和展現組件這兩類時,你會發現他們可以很方便的實現複用。性能優化

展現組件(Presentational Component)

  1. 關注頁面的展現效果(外觀)
  2. 內部能夠包含展現組件和容器組件,一般會包含一些本身的DOM標記和樣式(style)
  3. 一般容許經過this.props.children方式來包含其餘組件。
  4. 對應用程序的其餘部分沒有依賴關係,例如Flux操做或store。
  5. 不用關心數據是怎麼加載和變更的。
  6. 只能經過props的方式接收數據和進行回調(callback)操做。
  7. 不多擁有本身的狀態,即便有也是用於展現UI狀態的。
  8. 會被寫成函數式組件除非該組件須要本身的狀態,生命週期或者作一些性能優化。
Example:

Page,Header,Sidebar,UserInfo,Listbash

容器組件(Container Component)

  1. 關注應用的是如何工做的
  2. 內部能夠包含容器組件和展現組件,但一般沒有任何本身的DOM標記,除了一些包裝divs,而且從不具備任何樣式。
  3. 提供數據和行爲給其餘的展現組件或容器組件。
  4. 調用Flux操做並將它們做爲回調函數提供給展現組件。
  5. 每每是有狀態的,由於它們傾向於做爲數據源
  6. 一般使用高階組件生成,例如React Redux的connect(),Relay的createContainer()或Flux Utils的Container.create(),而不是手工編寫。
Example:

UserPage, FollowersSidebar, StoryContainer, FollowedUserListmarkdown

優勢(benifit)

  1. 展現和容器組件更好的分離,有助於更好的理解應用和UI
  2. 重用性高,展現組件能夠用於多個不一樣數據源。
  3. 展現組件就是你的調色板,能夠把他們放到單獨的頁面,在不影響應用程序的狀況下,讓設計師調整UI。
  4. 這迫使您提取諸如側邊欄,頁面,上下文菜單等「佈局組件」並使用this.props.children,而不是在多個容器組件中複製相同的標記和佈局。

什麼時候引入容器組件

我建議你從開始建立組件時只使用展現組件,到最後會意識到你傳遞了不少props到中間組件,而這些中間組件根本不會用到他們接收到的這些props,僅僅是向下傳遞。而當這些子組件須要更多的數據時,你須要重新配置這些中間組件。這個時候就須要引入容器組件了。使用容器組件的方式,您能夠將數據和行爲經過props傳遞給葉子組件,而沒必要麻煩一些不相關的中間組件。less

這是一個重構的過程,因此不比在第一次就作對。當你嘗試這種模式。在什麼時候應抽取爲容器組件你將會有一種直觀的感受。就像您知道什麼時候抽取函數同樣ide

二分法

重要的是你須要明白容器組件和展現組件之間不是技術上的區別,而是目的上的區別。函數

相比之下,這裏有幾個相關的(但不一樣的)技術區別:

  1. 有狀態【Stateful】和 無狀態【Stateless】:

    容器組件傾向於有狀態,展現組件傾向於無狀態,這不是硬性規定,由於容器組件和展現組件均可以是有狀態的。

  2. 類【Classes】 和 函數【Functions】:

    組件能夠被申明成類或函數,函數組件定義簡單,可是他缺少目前僅用於類的一些功能。雖然函數組件有不少限制,可是直到如今還有人使用,是由於函數組件容易理解,建議在不須要本身的state,lifecycle hooks,或性能優化的狀況下使用函數組件。這些僅適用於類組件。

//咱們將上邊的展現組件改寫成函數組件能夠以下
function TodoList(props){
    return (<div>
              <ul>
                    {props.todos.map((item,index)=>{
                        return <li key={item.id}>{item.name}</li>
                    })}
                </ul>  
        </div>)
}

複製代碼

可能不少人不清楚函數組件和類組件的區別,能夠去React的官網看一下函數組件和類組件

  1. 純粹【Pure】 和 不純粹 【Impure】:

    純粹:輸入什麼就輸出什麼,不會再其中作相應的變更。能夠被定義爲類或函數,能夠是無狀態或有狀態的,純組件的另外一個重要方面是它們不依賴props或state中的深度變更,因此他們的渲染性能能夠經過在shouldComponentUpdate()鉤子中進行淺層比較來優化,當前只有類能夠定義shouldComponentUpdate()方法。

不論是展現組件仍是容器組件都會有上面的二分特性。在我看來,展現組件每每是沒有狀態的純函數,而容器組件每每是有狀態的純類,這僅僅我的觀點並不是規則。

當不重要或說很難分清時,不要把分離容器組件和展現組件當作教條, 若是你不肯定該組件是容器組件仍是展現組件是,就暫時不要分離,寫成展現組件吧。

譯文來源:https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

相關文章
相關標籤/搜索