以前翻譯了兩篇關於Container&Presentational Component模型的文章,一篇是基礎的Container和Component的定義,另一篇是進階版,由於翻譯的太爛,感受有不少錯誤,因此只放原文連接。segmentfault
在這裏我想討論一下我本身對這個模型的一些想法。瀏覽器
注:便於書寫,下面統一把Container&Presentational Components模型翻譯爲容器&展現組件模型ide
注:下面圖片中的components文件夾指的是都是Presentational Components文件夾。性能
剛接觸React和這個模型的時候,我認爲項目的結構應該是這樣子的:
spa
Containers下面一個jsx文件就表明一個頁面,負責和後臺交互,負責和Redux進行connect,負責傳遞數據給component。在Router裏面放入對應頁面的Container翻譯
Components下面每一個jsx文件就表明頁面裏面全部的渲染的內容,負責渲染,和把從container拿到的數據放到頁面上3d
頂多把一些基礎的component分離出來,便於之後進行復用調試
但是才用兩天,就知道這麼搞有多麼坑了。容器組件模型的目的就是複用性,可讀性,可維護性,然而雖然咱們很成功的把後臺交互和頁面展現分離開了,可是看到這麼多代碼放在一塊兒,我沒有感受到任何複用性,可讀性,可維護性,那麼多代碼,並且都混合了業務邏輯,你讓我怎麼複用,理解,維護?!
component
痛定思痛,決定改一下,針對以前的問題,面向Component作出修改。基本的想法是這樣子的:儘可能拆分component,避免把全部的東西都放到一個文件裏面; 拆出可複用的組件,便於組件的複用;拆分邏輯複雜的模塊,增長模塊的可讀性和可維護性;因此關鍵字就是「拆、拆、拆」,拆出大好前程,拆出一片藍天...orm
因此結構成了這樣...
整個代碼結構複雜不少,不過主要的改變就是把基礎組件分離出來(Sidebar, Form之類),每個頁面也精細化。咱們能夠更清晰的看出每一個文件負責的功能,同時像Sidebar, Form這些組件均可以被多個不一樣的父組件調用。
固然,這不是結束,雖然上面的方法解決了咱們可讀性,可複用性,可維護性,可是也只針對Component的組件,在container中,依然會有不少的代碼堆積在哪裏。
並且還有一個很嚴重的問題,先看一個代碼邏輯結構圖:
咱們如今的數據是經過Container來進行管理的,因此若是Images須要圖片數據,那麼就須要經過Container->Top->Slide->Images這樣進行數據的傳遞,然而這些圖片數據跟中間的組件沒有任何關係,可是他們還必須把數據傳遞給下一級,就像公交車上,從後門遞公交卡到前門刷同樣,中間的人的心理OS實際上是:
固然代碼是沒有情感的,不會以爲厭煩,可是因爲中間每一層都須要傳遞數據給下層,一旦某些數據發生改變,就形成了中間層級的從新render,浪費了瀏覽器性能的同時,增大了調試的難度,並且接收數據的組件還要考慮「中間那些牲口們有沒有動個人數據」?!
因此,爲何必定要讓頂級的container做爲惟一的數據來源呢?
讀了這篇文章就知道,Container是能夠包含多個Container和Presentational Component的,因此咱們能夠適當的提高一些組件成爲container。若是老闆一我的直接管理不少員工,絕對會亂七八糟的,這個狀況下,leader這個角色就應運而生,咱們修改一下文件的結構:
如今,代碼的邏輯結構就變成這樣子:
做爲老闆的index.jsx,如今主要負責:
頁面的基礎配置,好比頁面的title,好比頁面總體內容結構的配置
頁面全局的數據的獲取和修改
做爲leader的Top, Content,如今主要負責:
和index.jsx進行溝通,獲取基礎配置和數據
負責整合須要的container和component
獲取和處理本身對應模塊的數據,並傳遞給下一層級
做爲presentational component的組件,就負責獲取數據並進行渲染
這麼作的好處是,分離了原來頂層container的繁重的任務,使代碼更加清晰。同時減小了從數據源到葉子結點的層級,減小了中間層級的數量和沒必要要的重複渲染。
固然,或許你會以爲以前舉的那個栗子,只有index.js下面有一層container,或許中間節點仍是太多。其實container裏面能夠包含container,根據須要,能夠建立不少container在不一樣的層級上。
View-Container-Presentational Component模型?這個名字是我本身編的,實際上是對上面說的結構的一個分離。我也看到過有人說Page-Module-Component模型,反正大概思路都是同樣的。
其實和上面的差很少,可是做爲一個大老闆來講,確定不能和一堆下級員工混在一塊兒,位置看起來有點混亂不說,"客人"(好比Router)來了,還不容易認。因此,我以爲應該給老闆一個包間,讓老闆們在本身的包間中,聽候客人的調遣。因此作出一點改動:
Okay,這就是個人最終方案,相比於最先的結構,這個結構更清晰,每一個模塊負責的功能也更明確,代碼可讀性、可複用性和可維護性更高。
Container和Presentational Component的區別?
Container一般會負責和服務端的溝通,還有一些業務邏輯的處理。他們一般只負責獲取數據,處理數據,處理狀態,但通常不知道如何去展現頁面。
Presentational Component一般不知道數據如何獲取,也不知道這些數據是作什麼用的,更不知道怎麼去操做這些數據,他們通常只負責頁面的渲染,把領導給的數據放到對應的位置。
固然一切都不是絕對的,容器組件模型只是一個指導思想,並非一個硬性的規定,你能夠按照本身的須要來進行改變。並且我在上面給了兩個通常,也是說明這些不是絕對的。Container固然能夠負責頁面的展現,老闆雖然大部分負責方向和管理,但誰規定老闆就不能寫代碼的?!一樣,Component也能夠負責獲取數據,舉個栗子,一個地圖的component,或者一個天氣預報的component,他們能夠從固定的地方獲取數據,並把數據渲染出來。
Container能夠包含Presentational Component?Presentational Component是否能夠包含Container?
Container能夠包含Container和Component。
可是Component通常不包含Container,雖然這篇文章的做者最後改口說,Component也能夠包含Container,可是我的以爲應該保證component的純淨性,若是包含Container,那麼就再也不純淨,或許在複用的時候,會出現誤差的狀況。
固然像我以前所說,一切都不是硬性規定,或許也只是由於我接觸的少因此沒有想到Presentational component須要包含container的狀況,一切都根據本身的須要進行調整。
如何知道何時要用container,何時要用Presentational component?
通常Presentational component應該是純淨(Pure)的,也就是說父級傳給他的數據不變,那麼渲染出來的結果也不該該發生任何變化。因此當一個組件須要業務邏輯處理,業務數據獲取,那麼能夠考慮使用container。若是不須要這些東西,那麼考慮使用Presentational component。固然,像以前所說的地圖,天氣預報,按照邏輯他們也屬於component,可是他們也獲取數據,處理數據。
當不知道該使用container仍是Presentational component的時候,那麼或許你在這個時候並不須要去決定這個問題。這種狀況下,能夠直接使用container來寫,當你的container變得愈來愈複雜,代碼量愈來愈多,邏輯愈來愈不清晰的時候,你就能夠考慮分離處更多的container和Presentational component來。
若是這篇文章指導的方向有錯誤,裏面有不少的問題,該怎麼辦?
歡迎指出和討論,一切問題都會認真回答,虛心接受。
若是我也答不出來,那我會看成沒看到...