本文譯自Presentational and Container Components,文章的作者是Dan Abramov,他同時也是Redux和Create React App的作者。 在實際使用React + Redux 技術棧的開發過程中,非常好的理解了容器型元件和展示型元件的概念是開發出易維護,可複用React App的基礎
在開發React應用的時候,我發現了一種極其簡單的開發模式。如果你已經用過一段時間的React,你也許已經發現了它。這篇文章已經講的很好了,但是我想補充幾點。
如果你將元件分為兩類,你會發現它們更容易被複用和理解。我把這兩類稱為容器型元件 和 展示型元件 ,但是我也聽說過其他名字,比如臃腫型元件和簡單型元件,智慧型元件和傻瓜型元件,有狀態元件和純元件,封裝型元件和元元件等等。它們不完全相同,但是在核心觀點上是相似的。
展示型元件
- 關心資料的展示方式
- 內部可能包含展示型元件和容器型元件,並且通常存在其他DOM元素及其樣式
- 允許通過
this.props.children
控制元件 - 不依賴app中的其它檔案,像Flux的actions或stores
- 不關心資料是如何載入和變化的
- 僅通過
props
接收資料和回撥函式 - 幾乎不用元件內的
state
(如果用到的話,也僅僅是維護UI狀態而不是資料狀態) - 除非需要用到
state
,生命週期函式或效能優化,通常寫成函式式元件, - 例如:
Page
,Sidebar
,Story
,UserInfo
,List
容器型元件
- 關心資料的運作方式
- 內部可能包含展示型元件和容器型元件,但是通常沒有任何用於自身的DOM元素,除了一些用於包裹元素的
div
標籤,並且不存在樣式 - 為展示型元件和容器型元件提供資料和運算元據的方法
- 呼叫Flux actions並以回撥函式的方式給展示型元件提供actions
- 通常是有狀態的,並且作為資料來源存在
- 通常由高階函式生成例如React Redux的
connect()
,Realy的createContainer
,或者Flux Utils的Container.create()
,而不是手寫的 - 例如:
UserPage
,FollowersSidebar
,StoryContainer
,FollowedUserList
為了清晰的區分這兩種元件,我把放在不同的資料夾中
這種方法的優勢
- 關注點分離。通過用這種方式開發元件,你可以更好的理解你的app和UI
- 更好的複用性。你可以在不同的資料來源中使用相同的展示型元件,也可以把它們放進不同容器型元件中更進一步的進行復用
- 展示型元件是你的app必不可少的"調色盤",你可以把它們放在一個獨立的頁面中,讓設計師隨意拖拽它們的變數而不改變應用的邏輯。在這個頁面上進行頁面快照迴歸測試
- 這種方法逼你去把用於佈局的元件抽出來,例如
Sidebar
,Page
,ContextMenu
。然後通過子元件的方式引入而不是在各個容器型元件中複製貼上已有的樣式和佈局
記住,元件不一定要輸出DOM元素,它們只需要提供UI之間的組合關係和分界
好好利用這一點
什麼時候引入容器?
我建議你先用展示型元件搭建你的app。最終你會意識到你給中間的元件傳遞了太多的props。有些元件並不使用這些props,而僅僅向下傳遞。並且當下層元件需要更多資料的時候,你必須重寫改寫所有的中間元件。這時候就需要引入一些容器型元件。通過這種方式,你可以從葉子節點元件獲取資料和方法,而不用考慮處於中間的元件。
這需要邊開發邊重構,所以沒有必要一次做對。隨著日常應用這種模式,你會元件培養出一種『這時候我該抽出一個Container』的直接,就像你已經知道什麼時候應該提取出一個函式一樣。我的Redux教程可能也會幫你一把
其他的二分法
展示型元件和容器型元件這種分類並非十分嚴格,這是按照它們的目的進行分類。
為了與之前的概念做比較,這是一些相關但不同的二分法
- 有狀態和無狀態 有些元件使用React的
setState()
方法,有些不用。容器型元件往往是有狀態的而展示型元件往往是無狀態的,這並不是一條鐵律。展示型元件也可以是有狀態的,容器型元件也可以是無狀態的 - 類和函式 從React0.14開始,元件既可以宣告為類也可以宣告為函式。函式式元件可以定義的更簡單但是也缺少一些只能在類元件中使用的特寫。有些限制可能未來會消除,但是在當下仍然是存在的。由於函式式元件更加易於理解,所以我建議你儘量的使用它。除非你需要
state
,生命週期函式,或者效能優化,這些特性只有在類元件中才可以使用。 - 純和非純 如果一個元件在輸入相同
props
的情況下總是輸出相同的結果,那我們稱這個元件為pure component。pure component既可以宣告為類元件也可以宣告為函式式元件,即可以是有狀態的也可以是無狀態的。另一個重要的方面是,pure component不依賴props
和state
的深層比對,所以可以在shouldComponentUpdate
方法中進行淺比較優化效能,但是在未來可能有很多變化。
展示型元件和容器型元件都可以放進以上任何一種二分法中。在我看來,展示型元件往往是無狀態的純函式元件,容器型元件往往是有狀態的純類元件。然而這並不是一種要求,而是一種現象,並且在一些特定的場景中我也確實見過完全相反的情況。
不要把展示型元件和容器型元件的劃分當成教條。有的時候沒有必要對二者進行區分。如果你不太確定一個元件是展示型元件還是容器型元件,也許現在還不是區分它的時候,別太心急!
例子
Michael Chan為我們用一個gist闡釋了上面的道理