摘要:本文想通過(guò)自己這一年的單頁(yè)應(yīng)用開(kāi)發(fā)經(jīng)驗(yàn),來(lái)對(duì)的開(kāi)發(fā)做一個(gè)總結(jié)。但是要知道,現(xiàn)如今頁(yè)面都比較復(fù)雜,一般的單頁(yè)應(yīng)用都需要一個(gè)可靠的數(shù)據(jù)流去處理,否則在日后維護(hù)方面會(huì)難度巨大。
本文想通過(guò)自己這一年的單頁(yè)應(yīng)用開(kāi)發(fā)經(jīng)驗(yàn),來(lái)對(duì)SPA的開(kāi)發(fā)做一個(gè)總結(jié)。
頁(yè)面開(kāi)發(fā)模式通常我們?cè)陂_(kāi)發(fā)頁(yè)面時(shí),都會(huì)拿到一份設(shè)計(jì)圖,假設(shè)我們拿到一份這樣的設(shè)計(jì)圖
對(duì)于頁(yè)面的開(kāi)發(fā),我總是遵循自上而下的設(shè)計(jì)模式去開(kāi)發(fā)。在這里首先會(huì)把頁(yè)面分為兩部分,頭部導(dǎo)航,和內(nèi)容主體。內(nèi)容主體又分為兩部分左側(cè)關(guān)注信息以及右側(cè)的動(dòng)態(tài)列表。如果按照這樣分,我們的組件編寫會(huì)像如下這樣
這樣寫其實(shí)沒(méi)什么問(wèn)題,把所有的細(xì)節(jié)全部隱藏在組件內(nèi)部,每個(gè)組件只要處理好自己就OK。但是要知道,現(xiàn)如今頁(yè)面都比較復(fù)雜,一般的單頁(yè)應(yīng)用都需要一個(gè)可靠的數(shù)據(jù)流去處理,否則在日后維護(hù)方面會(huì)難度巨大。這里假設(shè)我們使用了redux,在redux中,我們的數(shù)據(jù)都是從頂層往下傳,一般以route頁(yè)面為維度,去做connect,然后route頁(yè)面將所需的store以及action以props的形式分發(fā)。那就相當(dāng)于,整個(gè)頁(yè)面只有route組件是智能組件,其他組件盡可能寫成木偶組件。如果按照這樣的開(kāi)發(fā)模式去開(kāi)發(fā)左側(cè)關(guān)注列表組件,應(yīng)該是這樣的
//BodyLeft
而list組件應(yīng)該可能是這樣的
//List{data.map(item=>( - {item.name}
))}
這時(shí)如果route頁(yè)面想傳遞什么信息給左側(cè)列表,每次都要層層傳遞,少了一層,多了可能會(huì)有兩三層,這樣會(huì)寫很多沒(méi)用的信息,并且很不利于日后的維護(hù),因?yàn)槊看斡懈?,都要去改許多無(wú)用的地方(那些中間層)。
而我個(gè)人更傾向一種扁平化的組件設(shè)計(jì)風(fēng)格。
還是原來(lái)的頁(yè)面,如果采用扁平化的設(shè)計(jì)模式,設(shè)計(jì)出來(lái)的組件結(jié)構(gòu)是這樣的
//ps:組件命名隨便取的
首先最外層的布局是可以復(fù)用的。這也就意味著如果之后還有頁(yè)面是這樣,上下布局,下面又是左右布局的時(shí)候,可以拿來(lái)用。其次是數(shù)據(jù)的傳遞不需要像之前那樣層層傳遞,可以直接傳給想要的組件。
有人說(shuō)route頁(yè)面為什么不能這樣寫
...
也就是說(shuō)把之前的那些組件換成div不就好了。但是在組件設(shè)計(jì)哲學(xué)里,通常在connect的組件,也就是智能組件里,是不處理與view有關(guān)的東西,智能組件只處理數(shù)據(jù)和邏輯。而于視圖相關(guān)的東西全放在木偶組件去處理。好處是只要是邏輯處理,就會(huì)去找智能組件,而界面樣式之類,就會(huì)去找木偶組件,思路清晰,更低耦合高內(nèi)聚。
組件很多人對(duì)組件的理解是復(fù)用。其實(shí)組件化開(kāi)發(fā)還有一個(gè)好處就是模塊化。模塊化可以將一個(gè)復(fù)雜的問(wèn)題劃分為多個(gè),簡(jiǎn)單的問(wèn)題去處理。打個(gè)比方你的能力一次只能處理一個(gè)七十分的問(wèn)題,現(xiàn)在來(lái)了一個(gè)八十分的問(wèn)題,你一次性很難處理,經(jīng)常需要寫一寫,停頓一下,思考一會(huì),然后再寫一寫,直至完成;相反如果你采用模塊化的方式去解決,直接將這個(gè)八十分的問(wèn)題劃分為四個(gè)二十分的問(wèn)題,此時(shí),你只需要先搭建一個(gè)架子,讓這個(gè)四個(gè)二十分的模塊加起來(lái)能等于八十分,接著再去處理每個(gè)二十分的問(wèn)題就OK了。這其實(shí)也秉承了自上而下的設(shè)計(jì)風(fēng)格。
我通常將組件分為四類
智能組件
木偶組件
容器組件
高階組件
項(xiàng)目如果使用redux,智能組件通常是作為connect的那個(gè)組件,他只處理該組件下所有子組件的數(shù)據(jù)邏輯;而樣式,真實(shí)的dom結(jié)構(gòu),由木偶組件來(lái)負(fù)責(zé),他通常是stateless function,偶爾也有自己的state,但即使是state,也只處理與頁(yè)面展示有關(guān)的邏輯;容器組件很簡(jiǎn)單,如果把一個(gè)頁(yè)面比作一個(gè)人,容器組件就是人的頭,身體,和四肢。將頁(yè)面大致分類,通常的寫法是這樣的
//Body{this.props.children}
ps:為什么容器組件不直接寫成div上文說(shuō)過(guò)了。
如果說(shuō)前三類組件都在為頁(yè)面服務(wù),那么最后一個(gè)組件就是專門為組件服務(wù)的組件。高階組件就像高階函數(shù)一樣,將被修飾的組件作為參數(shù),同時(shí)也可以傳入其他配置參數(shù),最后返回一個(gè)被增強(qiáng)的組件,redux的connect就是一個(gè)高階組件,通常寫法是這樣的:
//高階組件 const Hoc = props => WrapComponent => { return class extends Component { render() { returnredux數(shù)據(jù)流; } }; }; // 使用 class WrapComponent extends Component{ render(){ return } } export default Hoc()(WrapComponent)
在redux數(shù)據(jù)流管理里,行業(yè)里有很多最佳實(shí)踐,我這里就當(dāng)拋磚引玉。
我認(rèn)為一般頁(yè)面邏輯不是很復(fù)雜的項(xiàng)目,簡(jiǎn)單的使用redux redux-thunk redux-action就夠了,如果需要處理的請(qǐng)求很復(fù)雜,為了避免回調(diào)地獄,可以使用redux-saga。通常我們?cè)趯?duì)數(shù)據(jù)從頂部往下分發(fā)的時(shí)候,需要以一個(gè)維度為基點(diǎn)來(lái)做connect,這個(gè)維度一般是route頁(yè)面。對(duì)于router,現(xiàn)在也基本達(dá)成了共識(shí),那就是router的數(shù)據(jù)狀態(tài)也是redux數(shù)據(jù)的一種,它與view無(wú)關(guān),因此使用react-redux-router將router與redux結(jié)合在一起是一個(gè)比較好的做法。
在redux里,有一個(gè)比較有爭(zhēng)議的點(diǎn)是,關(guān)于頁(yè)面的狀態(tài),是否要放在redux里。有人認(rèn)為redux就應(yīng)該只放數(shù)據(jù),即后臺(tái)的數(shù)據(jù)和部分前臺(tái)自己存儲(chǔ)的數(shù)據(jù);但是我認(rèn)為,我們頁(yè)面在開(kāi)發(fā)過(guò)程中,頁(yè)面的展示邏輯通常與后臺(tái)的數(shù)據(jù)是非常耦合的,可能一個(gè)按鈕的狀態(tài),一個(gè)icon的顏色,都與后臺(tái)的數(shù)據(jù)有關(guān),那么如果強(qiáng)行拆分,就會(huì)變成對(duì)于一個(gè)流程,我們要先去redux里處理后臺(tái)數(shù)據(jù),處理好之后,再去智能組件里根據(jù)redux數(shù)據(jù)處理內(nèi)部state(頁(yè)面的狀態(tài)),這樣很麻煩,也很難維護(hù)。我自己的做法是,每一個(gè)流程,只對(duì)應(yīng)一個(gè)action,這個(gè)action內(nèi)部再去根據(jù)不同的參數(shù)去處理不同的數(shù)據(jù),直至頁(yè)面正常反應(yīng)這個(gè)操作為止。
總的來(lái)說(shuō),我們中很多人包括我自己,給view層賦予了太多的職能和責(zé)任,造成redux的價(jià)值沒(méi)有發(fā)揮出來(lái),view里跑著各種state,后期難以維護(hù),這無(wú)疑是本末倒置的。寫這篇總結(jié)也是對(duì)我最近寫項(xiàng)目的一些反思,希望能有更多的人一起討論,謝謝。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83327.html
摘要:本文只是對(duì)官方文檔和對(duì)官方的個(gè)人學(xué)習(xí)總結(jié),說(shuō)得不夠完整的請(qǐng)見(jiàn)諒本文主要對(duì)以下幾方面內(nèi)容對(duì)的內(nèi)容進(jìn)行分析總結(jié)出現(xiàn)的原因的總體原理當(dāng)中的數(shù)據(jù)預(yù)取在編寫代碼時(shí)候的限制的構(gòu)建原理出現(xiàn)的原因單頁(yè)應(yīng)用有一個(gè)很大的缺點(diǎn)就是問(wèn)題,搜索引擎目前只能對(duì)同步的進(jìn) 本文只是對(duì)Vue.js官方SSR文檔和對(duì)官方hackernews demo的個(gè)人學(xué)習(xí)總結(jié),說(shuō)得不夠完整的請(qǐng)見(jiàn)諒 本文主要對(duì)以下幾方面內(nèi)容對(duì)Vue....
摘要:?jiǎn)雾?yè)應(yīng)用的原理從早起的根據(jù)的變化,到根據(jù)的的變化,實(shí)現(xiàn)無(wú)刷新條件下的頁(yè)面重新渲染。那么在單頁(yè)應(yīng)用中是如何監(jiān)聽(tīng)的變化呢,本文將總結(jié)一下,如何在單頁(yè)頁(yè)面中優(yōu)雅的監(jiān)聽(tīng)的變化。在下幾章中,重點(diǎn)介紹一下如何監(jiān)聽(tīng)的改變。 ??單頁(yè)應(yīng)用的原理從早起的根據(jù)url的hash變化,到根據(jù)H5的history的變化,實(shí)現(xiàn)無(wú)刷新條件下的頁(yè)面重新渲染。那么在單頁(yè)應(yīng)用中是如何監(jiān)聽(tīng)url的變化呢,本文將總結(jié)一下,...
摘要:?jiǎn)雾?yè)應(yīng)用的原理從早起的根據(jù)的變化,到根據(jù)的的變化,實(shí)現(xiàn)無(wú)刷新條件下的頁(yè)面重新渲染。那么在單頁(yè)應(yīng)用中是如何監(jiān)聽(tīng)的變化呢,本文將總結(jié)一下,如何在單頁(yè)頁(yè)面中優(yōu)雅的監(jiān)聽(tīng)的變化。在下幾章中,重點(diǎn)介紹一下如何監(jiān)聽(tīng)的改變。 ??單頁(yè)應(yīng)用的原理從早起的根據(jù)url的hash變化,到根據(jù)H5的history的變化,實(shí)現(xiàn)無(wú)刷新條件下的頁(yè)面重新渲染。那么在單頁(yè)應(yīng)用中是如何監(jiān)聽(tīng)url的變化呢,本文將總結(jié)一下,...
摘要:?jiǎn)雾?yè)應(yīng)用的原理從早起的根據(jù)的變化,到根據(jù)的的變化,實(shí)現(xiàn)無(wú)刷新條件下的頁(yè)面重新渲染。那么在單頁(yè)應(yīng)用中是如何監(jiān)聽(tīng)的變化呢,本文將總結(jié)一下,如何在單頁(yè)頁(yè)面中優(yōu)雅的監(jiān)聽(tīng)的變化。在下幾章中,重點(diǎn)介紹一下如何監(jiān)聽(tīng)的改變。 ??單頁(yè)應(yīng)用的原理從早起的根據(jù)url的hash變化,到根據(jù)H5的history的變化,實(shí)現(xiàn)無(wú)刷新條件下的頁(yè)面重新渲染。那么在單頁(yè)應(yīng)用中是如何監(jiān)聽(tīng)url的變化呢,本文將總結(jié)一下,...
閱讀 2004·2021-11-22 09:34
閱讀 3201·2021-09-28 09:35
閱讀 13814·2021-09-09 11:34
閱讀 3682·2019-08-29 16:25
閱讀 2883·2019-08-29 15:23
閱讀 2086·2019-08-28 17:55
閱讀 2482·2019-08-26 17:04
閱讀 3084·2019-08-26 12:21