摘要:同時(shí)減少了從數(shù)據(jù)源到葉子結(jié)點(diǎn)的層級(jí),減少了中間層級(jí)的數(shù)量和不必要的重復(fù)渲染。模型這個(gè)名字是我自己編的,其實(shí)是對(duì)上面說(shuō)的結(jié)構(gòu)的一個(gè)分離。當(dāng)然,像之前所說(shuō)的地圖,天氣預(yù)報(bào),按照邏輯他們也屬于,但是他們也獲取數(shù)據(jù),處理數(shù)據(jù)。
之前翻譯了兩篇關(guān)于Container&Presentational Component模型的文章,一篇是基礎(chǔ)的Container和Component的定義,另外一篇是進(jìn)階版,因?yàn)榉g的太爛,感覺(jué)有很多錯(cuò)誤,所以只放原文鏈接。
在這里我想討論一下我自己對(duì)這個(gè)模型的一些想法。
注:便于書(shū)寫(xiě),下面統(tǒng)一把Container&Presentational Components模型翻譯為容器&展示組件模型
注:下面圖片中的components文件夾指的是都是Presentational Components文件夾。
基于容器&展示組件模型的目錄結(jié)構(gòu) Round 1:剛接觸React和這個(gè)模型的時(shí)候,我認(rèn)為項(xiàng)目的結(jié)構(gòu)應(yīng)該是這樣子的:
Containers下面一個(gè)jsx文件就代表一個(gè)頁(yè)面,負(fù)責(zé)和后臺(tái)交互,負(fù)責(zé)和Redux進(jìn)行connect,負(fù)責(zé)傳遞數(shù)據(jù)給component。在Router里面放入對(duì)應(yīng)頁(yè)面的Container
Components下面每個(gè)jsx文件就代表頁(yè)面里面所有的渲染的內(nèi)容,負(fù)責(zé)渲染,和把從container拿到的數(shù)據(jù)放到頁(yè)面上
頂多把一些基礎(chǔ)的component分離出來(lái),便于以后進(jìn)行復(fù)用
可是才用兩天,就知道這么搞有多么坑了。容器組件模型的目的就是復(fù)用性,可讀性,可維護(hù)性,然而雖然我們很成功的把后臺(tái)交互和頁(yè)面展示分離開(kāi)了,但是看到這么多代碼放在一起,我沒(méi)有感覺(jué)到任何復(fù)用性,可讀性,可維護(hù)性,那么多代碼,而且都混合了業(yè)務(wù)邏輯,你讓我怎么復(fù)用,理解,維護(hù)?!
痛定思痛,決定改一下,針對(duì)之前的問(wèn)題,面向Component做出修改。基本的想法是這樣子的:盡量拆分component,避免把所有的東西都放到一個(gè)文件里面; 拆出可復(fù)用的組件,便于組件的復(fù)用;拆分邏輯復(fù)雜的模塊,增加模塊的可讀性和可維護(hù)性;所以關(guān)鍵字就是“拆、拆、拆”,拆出大好前程,拆出一片藍(lán)天...
所以結(jié)構(gòu)成了這樣...
整個(gè)代碼結(jié)構(gòu)復(fù)雜很多,不過(guò)主要的改變就是把基礎(chǔ)組件分離出來(lái)(Sidebar, Form之類),每一個(gè)頁(yè)面也精細(xì)化。我們可以更清晰的看出每個(gè)文件負(fù)責(zé)的功能,同時(shí)像Sidebar, Form這些組件都可以被多個(gè)不同的父組件調(diào)用。
當(dāng)然,這不是結(jié)束,雖然上面的方法解決了我們可讀性,可復(fù)用性,可維護(hù)性,但是也只針對(duì)Component的組件,在container中,依然會(huì)有很多的代碼堆積在哪里。
而且還有一個(gè)很?chē)?yán)重的問(wèn)題,先看一個(gè)代碼邏輯結(jié)構(gòu)圖:
我們現(xiàn)在的數(shù)據(jù)是通過(guò)Container來(lái)進(jìn)行管理的,所以如果Images需要圖片數(shù)據(jù),那么就需要通過(guò)Container->Top->Slide->Images這樣進(jìn)行數(shù)據(jù)的傳遞,然而這些圖片數(shù)據(jù)跟中間的組件沒(méi)有任何關(guān)系,但是他們還必須把數(shù)據(jù)傳遞給下一級(jí),就像公交車(chē)上,從后門(mén)遞公交卡到前門(mén)刷一樣,中間的人的心理OS其實(shí)是:
當(dāng)然代碼是沒(méi)有情感的,不會(huì)覺(jué)得厭煩,但是由于中間每一層都需要傳遞數(shù)據(jù)給下層,一旦某些數(shù)據(jù)發(fā)生改變,就造成了中間層級(jí)的重新render,浪費(fèi)了瀏覽器性能的同時(shí),增大了調(diào)試的難度,而且接收數(shù)據(jù)的組件還要考慮“中間那些牲口們有沒(méi)有動(dòng)我的數(shù)據(jù)”?!
Round 3:所以,為什么一定要讓頂級(jí)的container作為唯一的數(shù)據(jù)來(lái)源呢?
讀了這篇文章就知道,Container是可以包含多個(gè)Container和Presentational Component的,所以我們可以適當(dāng)?shù)奶嵘恍┙M件成為container。如果老板一個(gè)人直接管理很多員工,絕對(duì)會(huì)亂七八糟的,這個(gè)情況下,leader這個(gè)角色就應(yīng)運(yùn)而生,我們修改一下文件的結(jié)構(gòu):
現(xiàn)在,代碼的邏輯結(jié)構(gòu)就變成這樣子:
作為老板的index.jsx,現(xiàn)在主要負(fù)責(zé):
頁(yè)面的基礎(chǔ)配置,比如頁(yè)面的title,比如頁(yè)面整體內(nèi)容結(jié)構(gòu)的配置
頁(yè)面全局的數(shù)據(jù)的獲取和修改
作為leader的Top, Content,現(xiàn)在主要負(fù)責(zé):
和index.jsx進(jìn)行溝通,獲取基礎(chǔ)配置和數(shù)據(jù)
負(fù)責(zé)整合需要的container和component
獲取和處理自己對(duì)應(yīng)模塊的數(shù)據(jù),并傳遞給下一層級(jí)
作為presentational component的組件,就負(fù)責(zé)獲取數(shù)據(jù)并進(jìn)行渲染
這么做的好處是,分離了原來(lái)頂層container的繁重的任務(wù),使代碼更加清晰。同時(shí)減少了從數(shù)據(jù)源到葉子結(jié)點(diǎn)的層級(jí),減少了中間層級(jí)的數(shù)量和不必要的重復(fù)渲染。
當(dāng)然,或許你會(huì)覺(jué)得之前舉的那個(gè)栗子,只有index.js下面有一層container,或許中間節(jié)點(diǎn)還是太多。其實(shí)container里面可以包含container,根據(jù)需要,可以創(chuàng)建很多container在不同的層級(jí)上。
Round 4View-Container-Presentational Component模型?這個(gè)名字是我自己編的,其實(shí)是對(duì)上面說(shuō)的結(jié)構(gòu)的一個(gè)分離。我也看到過(guò)有人說(shuō)Page-Module-Component模型,反正大概思路都是一樣的。
其實(shí)和上面的差不多,但是作為一個(gè)大老板來(lái)說(shuō),肯定不能和一堆下級(jí)員工混在一起,位置看起來(lái)有點(diǎn)混亂不說(shuō),"客人"(比如Router)來(lái)了,還不容易認(rèn)。所以,我覺(jué)得應(yīng)該給老板一個(gè)包間,讓老板們?cè)谧约旱陌g中,聽(tīng)候客人的調(diào)遣。所以做出一點(diǎn)改動(dòng):
Okay,這就是我的最終方案,相比于最早的結(jié)構(gòu),這個(gè)結(jié)構(gòu)更清晰,每個(gè)模塊負(fù)責(zé)的功能也更明確,代碼可讀性、可復(fù)用性和可維護(hù)性更高。
最后自問(wèn)自答環(huán)節(jié)Container和Presentational Component的區(qū)別?
Container通常會(huì)負(fù)責(zé)和服務(wù)端的溝通,還有一些業(yè)務(wù)邏輯的處理。他們通常只負(fù)責(zé)獲取數(shù)據(jù),處理數(shù)據(jù),處理狀態(tài),但一般不知道如何去展示頁(yè)面。
Presentational Component通常不知道數(shù)據(jù)如何獲取,也不知道這些數(shù)據(jù)是做什么用的,更不知道怎么去操作這些數(shù)據(jù),他們一般只負(fù)責(zé)頁(yè)面的渲染,把領(lǐng)導(dǎo)給的數(shù)據(jù)放到對(duì)應(yīng)的位置。
當(dāng)然一切都不是絕對(duì)的,容器組件模型只是一個(gè)指導(dǎo)思想,并不是一個(gè)硬性的規(guī)定,你可以按照自己的需要來(lái)進(jìn)行改變。而且我在上面給了兩個(gè)一般,也是說(shuō)明這些不是絕對(duì)的。Container當(dāng)然可以負(fù)責(zé)頁(yè)面的展示,老板雖然大部分負(fù)責(zé)方向和管理,但誰(shuí)規(guī)定老板就不能寫(xiě)代碼的?!同樣,Component也可以負(fù)責(zé)獲取數(shù)據(jù),舉個(gè)栗子,一個(gè)地圖的component,或者一個(gè)天氣預(yù)報(bào)的component,他們可以從固定的地方獲取數(shù)據(jù),并把數(shù)據(jù)渲染出來(lái)。
Container可以包含Presentational Component?Presentational Component是否可以包含Container?
Container可以包含Container和Component。
但是Component一般不包含Container,雖然這篇文章的作者最后改口說(shuō),Component也可以包含Container,但是個(gè)人覺(jué)得應(yīng)該保證component的純凈性,如果包含Container,那么就不再純凈,或許在復(fù)用的時(shí)候,會(huì)出現(xiàn)偏差的情況。
當(dāng)然像我之前所說(shuō),一切都不是硬性規(guī)定,或許也只是因?yàn)槲医佑|的少所以沒(méi)有想到Presentational component需要包含container的情況,一切都根據(jù)自己的需要進(jìn)行調(diào)整。
如何知道什么時(shí)候要用container,什么時(shí)候要用Presentational component?
一般Presentational component應(yīng)該是純凈(Pure)的,也就是說(shuō)父級(jí)傳給他的數(shù)據(jù)不變,那么渲染出來(lái)的結(jié)果也不應(yīng)該發(fā)生任何變化。所以當(dāng)一個(gè)組件需要業(yè)務(wù)邏輯處理,業(yè)務(wù)數(shù)據(jù)獲取,那么可以考慮使用container。如果不需要這些東西,那么考慮使用Presentational component。當(dāng)然,像之前所說(shuō)的地圖,天氣預(yù)報(bào),按照邏輯他們也屬于component,但是他們也獲取數(shù)據(jù),處理數(shù)據(jù)。
當(dāng)不知道該使用container還是Presentational component的時(shí)候,那么或許你在這個(gè)時(shí)候并不需要去決定這個(gè)問(wèn)題。這種情況下,可以直接使用container來(lái)寫(xiě),當(dāng)你的container變得越來(lái)越復(fù)雜,代碼量越來(lái)越多,邏輯越來(lái)越不清晰的時(shí)候,你就可以考慮分離處更多的container和Presentational component來(lái)。
如果這篇文章指導(dǎo)的方向有錯(cuò)誤,里面有很多的問(wèn)題,該怎么辦?
歡迎指出和討論,一切問(wèn)題都會(huì)認(rèn)真回答,虛心接受。
如果我也答不出來(lái),那我會(huì)當(dāng)作沒(méi)看到...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86590.html
摘要:在線注冊(cè)賬號(hào),數(shù)據(jù)存儲(chǔ)于。年了,還不使用的異步控制體系。過(guò)度對(duì)數(shù)據(jù)模型進(jìn)行裝飾的結(jié)果便是高耦合,這跟我初衷是基于在線存儲(chǔ)數(shù)據(jù)有關(guān)。 為什么又是Todo,全世界的初學(xué)者都在做todo嗎?可能很多人要問(wèn)這句話,其實(shí)這句話可以等同于: 為什么你做了個(gè)云音樂(lè)播放器? 為什么你做了個(gè)新聞閱讀APP? 為什么你做了個(gè)VUE/REACT版本的CNODE? 究其本質(zhì),這幾個(gè)應(yīng)用都是data-map...
摘要:對(duì)于很多中間組件來(lái)說(shuō),他們并不需要這些,但是他們還必須傳遞給下一級(jí)組件。更傾向于,而更傾向于,當(dāng)然這并不是絕對(duì)的。這是篇文章翻譯自的 這是篇文章翻譯自medium的:Presentational and Container Components 譯者語(yǔ):這篇文章是緊接著對(duì)我上一篇翻譯的擴(kuò)充,對(duì)Container Component模式描述的更加細(xì),解決了我很多開(kāi)發(fā)中的困惑。 Prese...
摘要:在一個(gè)應(yīng)用中,如何通過(guò)和端進(jìn)行交互這個(gè)問(wèn)題曾經(jīng)困擾了我一段時(shí)間,經(jīng)過(guò)學(xué)習(xí)實(shí)踐,有了一點(diǎn)心得體會(huì),寫(xiě)出來(lái)和大家分享一下。組件和一樣,和進(jìn)行交互,將獲取的通過(guò)向下傳遞給組件。不足被設(shè)計(jì)用來(lái)和服務(wù)器一起運(yùn)行,并不能很好的和第三方服務(wù)交互。 在一個(gè)react應(yīng)用中,如何通過(guò)ajax和server端進(jìn)行交互這個(gè)問(wèn)題曾經(jīng)困擾了我一段時(shí)間,經(jīng)過(guò)學(xué)習(xí)實(shí)踐,有了一點(diǎn)心得體會(huì),寫(xiě)出來(lái)和大家分享一下。 總的...
摘要:如在中在中,聚合積累的結(jié)果是當(dāng)前的對(duì)象。被稱為副作用,在我們的應(yīng)用中,最常見(jiàn)的就是異步操作。至于為什么我們這么糾結(jié)于純函數(shù),如果你想了解更多可以閱讀,或者它的中文譯本函數(shù)式編程指南。 DvaJS: React and redux based, lightweight and elm-style framework. https://dvajs.com/ 實(shí)例項(xiàng)目源碼:https://g...
摘要:更多相關(guān)介紹請(qǐng)看這特點(diǎn)僅僅只是虛擬最大限度減少與的交互類似于使用操作單向數(shù)據(jù)流很大程度減少了重復(fù)代碼的使用組件化可組合一個(gè)組件易于和其它組件一起使用,或者嵌套在另一個(gè)組件內(nèi)部。在使用后,就變得很容易維護(hù),而且數(shù)據(jù)流非常清晰,容易解決遇到的。 歡迎移步我的博客閱讀:《React 入門(mén)實(shí)踐》 在寫(xiě)這篇文章之前,我已經(jīng)接觸 React 有大半年了。在初步學(xué)習(xí) React 之后就正式應(yīng)用到項(xiàng)...
閱讀 1960·2021-11-24 11:16
閱讀 3292·2021-09-10 10:51
閱讀 3268·2021-08-03 14:03
閱讀 1295·2019-08-29 17:03
閱讀 3279·2019-08-29 12:36
閱讀 2269·2019-08-26 14:06
閱讀 522·2019-08-23 16:32
閱讀 2756·2019-08-23 13:42