翻譯:展示元件和容器元件

我很可愛你信不信發表於2019-03-02

原文連結:Presentational and Container Components

我找到了一個當我們在寫react應用時非常有用的模式。如果你寫過一段時間的react,你可能已經發現了它。這篇文站很好的解釋了它,但是我想補充一些觀點。

如果將元件劃分為兩類,你會發現元件重用起來更加容易。我把這兩類稱為ContainerPresentational。也有其他叫法,FatSkinny, SmartDumb, StatefulPure, ScreensComponents等等。這些都不完全相同,但是核心思想是相似的。

我的presentational元件:

  • 關心事物如何展示;
  • 也許會同時包含展示類元件和容器元件,並且通常有一些DOM操作和自己的樣式;
  • 通常允許this.props.chidren放在容器裡;
  • 對應用的其餘部分沒有依賴,比如Flux actions或者stores
  • 不會說明資料是如何載入和變化的;
  • 只通過props接受資料和回撥函式;
  • 幾乎沒有自己的state(即使有,也是UI相關的,而不是data相關的);
  • 通常被寫作函式式元件除非需要狀態、生命週期的鉤子、效能優化;
  • 例子:Page, Sidebar, Story, UserInfo, List

我的container元件:

  • 關心事物如何運作;
  • 也許會同時包含展示類元件和容器元件,但是除了一些用來包含元素的div通常不會其他有DOM操作,並且不會包含任何樣式;
  • presentational元件或其他container元件提供資料和行為;
  • 通常是有狀態的,因為它們往往作為資料來源;
  • 通常使用像React Reduxconnect()RelaycreateContainer()Flux UtilsContainer.create()這樣的高階元件來生成,而不是手動編寫;
  • 例子:UserPage, FollowersSidebar, StoryContainer, FollowedUserList

這種方式的好處:

  • 更好的關注分離。通過這種方式編寫元件,你能更好的理解你的應用和試圖;
  • 更好的可重用性。你可以將相同的presentational元件和完全不同的狀態組合在一起,並將這些轉化為可進一步重用的獨立的容器元件;
  • presentational元件本質上是你應用的“調色盤”。你可以將它們放在一個單頁面,設計師不接觸應用的邏輯就可以調整所有的變化;
  • 這迫使你提取你的佈局元件比如Sidebar, Page, ContextMenu,使用this.props.children而不是在幾個容器元件之間複製標籤和佈局。

什麼時候引入Containers?

我建議你一開始只用presentational元件來構建應用。最後你會意識到通過中間元件傳遞了太多的props。當你注意到一些元件並不使用它們收到的props而幾乎只是向下傳遞,並且當子元件需要更多資料的時候你得重寫所有的中間元件,這就是應該引入container元件的好時候了。通過這種方式,你可以通過葉元件得到需要的資料和行為,而不會加重元件樹中不相關的元件。

這是一個持續重構的過程,所以不要嘗試一次就做的好。當你嘗試這種模式,你會形成一種什麼時候該提取一個container的直覺,就像你知道什麼時候該提取一個函式一樣。我的free Redux Egghead series也能在這方面幫助你。

其他分類

重要的是要理解presentational元件和container元件之間的區別不是一個技術問題,相反,區別在於它們的目的。

相比之下,這裡有一些相關(但不同!)技術的區別:

  • 有狀態的和無狀態的。一些元件使用 ReactsetState()方法但有些不使用,當presentational元件往往是無狀態的,container元件往往是有狀態,這不是一個硬性的規則。presentational元件可以是有狀態的,container元件也可以是無狀態的。
  • 類和函式React0.14開始,元件可以以函式或類的方式宣告。函式式元件定義更簡單,但是缺乏一些類特有的功能。這些限制也許在未來會解決但是如今確實存在。由於函式式元件更容易理解,所以我建議你使用函式式元件,除非你需要狀態、生命週期鉤子和效能優化這些目前只提供給類的功能。
  • 純和不純。如果給一個元件輸入相同的stateprops,保證會輸出相同的結果,大家稱這樣的元件為純元件。純元件可以使用函式或類來宣告,並且可以是有狀態的或無狀態的。純元件另一個重要的方面是它們不依賴propsstate的深度變化,所以它們的渲染效能可以在shouldComponentUpdate()鉤子函式裡通過淺比較進行優化。目前只支援在類中定義shouldComponentUpdate(),但是未來也許會改變。

presentational元件和container元件都可以是任意一種狀態。以我的經驗,presentational元件往往是無狀態的純函式(pure functions),container元件往往是有狀態的純類(pure classes),然而這只是觀察得來的結論而不是一種規則,我曾經也看到過完全相反但是合理的情況。

不要把分離presentational元件和container元件當做一種教條。有時候並沒那麼重要或很難劃清界限,如果你不確定一個元件該是presentational元件或container元件,也許是決定的太早了。別擔心!

相關文章