簡單說明一下代碼文件結構背后的想法。
一、模塊的概念
App
一個模塊可以簡單理解為一個Web App中的子App.
- Module: main
- Module: grapher
- Module: work
- Module: user
每個模塊應該負責自己的內部MVC,同時相互之間盡量獨立,并通過預先定義的接口來交互/交換數據。
View
根據Redux的編程規范,所有React Component分兩種:
- Presentational / Stateless / Dumb Component:說白了這種Component只負責展示,數據和回調都來自props,本身沒有state. (所有名字里Dumb最短,就用這個名字吧)
- Container / Smart Component:負責交互Redux中的數據的Component。(慣例,用最短的名字:Smart)
然后從項目的角度繼續細分,Dumb Component分為2種:
- 用于布局的Layout:項目專屬。
- 可以復用的Web Component:高可復用性。
對于高可復用的Web Component,應該放在獨立的類似arsenal包里,作為組件引入進來。
這樣的話,Module就應該包含這些View內容:
- containers:Smart Component,供Route用。
- layouts:項目專屬的Dumb Component.
Model
根據Redux的用法,這部分包含:
- Action:意圖,由Redux-thunk擴展之后的版本。
- Reducer:這里要遵守pure function的概念。
這樣,Module就應該包含這些Model內容:
- actions:存放所有的actions常亮和action creators.
- reducers:存放所有reducers.
注:
這里有個建議:reducer在Module中或多或少,多的時候創建文件夾reducers,少的時候直接一個reducers.js文件,這里都用復數格式。作為export的情況,則用單數。
綜合起來
綜合以上的說明,View和Model部分在Module中區分好,還要暴露特定的exports給App。
所以Module目錄下增加2個文件:
- route.js:這個文件引用所有給route用的Component(smart or dumb),組建局部Route,并輸出這個Route.
- reducer.js:這個文件combine所有本Module中的Reducers,然后輸出。
- 也許會有的interface.js:這個作為api的出口。
注:
- 由于route中有需要在跳轉前進行init或auth,因此export routeFactory 而不是單純輸出route. 這個factory接收一個store參數,用于在init中發dispatch,或是auth中getState( ) 做邏輯判斷。
- 關于interface.js:有時候要去校驗用戶是否登陸,如果直接用store.getState( )的話,要依賴于用戶reducer的掛載點。把mount變量從user這個Module里引過來,不如直接讓user提供API來調用。不過這個怎么用,還要結合Smart的生成研究一下。
結論
各Module按照功能區分開之后,App作為整個應用的入口(index.js),就要負責把Model和View組合起來,所以項目源碼目錄下放這兩個文件:
- index.js:App入口,負責引入store,組裝各種東西,包括Model的Route.
- store.js:項目的store(Redux就一個store),負責import所有module下的reducer.
然后得到項目的結構如下:
- index.js:App入口
- store.js:項目的store
- main/:Module main
- route.js:export View / Route
- containers/:Module下的Smart Components
- layouts/:項目專屬Dumb Components
- reducer.js:export Model / Reducer
- reducers/:項目reducers
- actions/:項目actions
- grapher/:Module grapher
- work/:Module work
- user/:Module user