Next.js踩坑入門系列(六) —— 再次重構目錄
上一節引入了redux以及使用redux-saga來進行非同步函式的處理,而上一節的目錄只是簡單的引入redux而已,redux可是相當龐大和複雜的,並且也算是個人習慣了吧。action分離,reducer分離,狀態元件container等等。我喜歡把這些東西劃分的清清楚楚,這樣一個專案維護起來才會方便~這一節就從頭到尾來進行目錄的劃分,因為Next.js和原本的React SPA專案有一定的區別,主要體現在路由部分,所以我也是按照自己的理解和舒服的方式進行目錄重構!
重構完的目錄
// ================ 目錄結構 ================== // —————— | -- asserts// ant-design全域性less變數設定資料夾 | -- components// React展示元件(也就是UI元件)資料夾 | -- constants// 整個應用的常量資料夾 | -- ActionsTypes.js// 存放所有action type的常量檔案 | -- ApiUrlForBE.js// 存放所有後端資料的apiUrl | -- ... | -- containers// React狀態元件資料夾 | -- pages// Next.js路由資料夾 | -- redux | -- actions// 處理整個應用所有的action | -- middlewares // 中介軟體,處理各種特殊情況,比如獲取失敗之後的message提醒 | -- reducers// 處理整個應用所有的reducer | -- sagas// 處理整個應用所有的saga | -- store.js | -- static// 存放整個應用所有的靜態資源(如圖片等) | -- .babelrc | -- .eslintrc | -- .gitignore | -- next.config.js// Next.js配置檔案 | -- package.json | -- server.js// 服務端server檔案 | ... 複製程式碼
原諒我臭不要臉一下,個人認為這個結構還是非常清晰的,只不過可能新手寫起來可能會覺得有些繁瑣,不過專案大的情況下,state樹很大,這種結構非常的清晰~
重構actions
其實actions完全可以放在一個檔案裡使用,不過專案龐大了以後維護起來還是有些麻煩的,所以按照元件化思想,每一個元件對應一個action,或者每一個大功能塊對應一個action還是比較合理的。
-- redux | -- actions |-- home.js // 處理首頁action |-- user.js // 處理與使用者有關action |...// 其他action 複製程式碼
重構reducers
reducer部分肯定是要分離的,因為redux的官方為我們提供combineReducer這個API就是合併不同元件的reducer的,所以可以理解為redux的reducer推薦就是根據元件進行劃分的~就如同整個應用只有一個狀態樹一樣,每一個reducer負責處理樹的不同枝葉派發出來的action。具體reducer內容還是去看redux官方文件吧。
重構sagas
-- redux | -- reducers |-- home// 首頁部分reducer |-- user// 使用者相關reducer |...// 其他reducer | index.js// rootReducer,由combineReducer生成 複製程式碼
抽離container
這裡需要特別說明一下~~~由於Next.js的特殊原因,其實已經做到了UI元件的分離,其實這一層container完全可以由pages資料夾代替,也就是可以用路由元件通過react-redux的connect函式封裝一下,這樣就變成了一個帶狀態的路由元件,不知道大家明不明白我說的話。。。下面是兩種方法,大家按需自己採取,以UserList元件為例:
- 第一種,抽離container
// /conatiners/user/UserList.js import { connect } from 'react-redux'; import { fetchUserListData } from '../../redux/actions/user'; import UserList from '../../components/User/UserList'; const mapStateToProps = state => ({ list: state.user.list.list, }); const mapDispatchToProps = dispatch => ({ fetchUserListData() { dispatch(fetchUserListData()); } }); export default connect(mapStateToProps, mapDispatchToProps)(UserList); // pages/user/userList.js import UserList from '../../containers/user/UserList'; import { fetchUserListData } from '../../redux/actions/user'; // 這部分內容下一章節講~ UserList.getInitialProps = async (props) => { const { store, isServer } = props.ctx; if (store.getState().user.list.list.length === 0) { store.dispatch(fetchUserListData()); } return { isServer }; }; export default UserList; 複製程式碼
簡單來說其實就是路由元件匯入的是狀態組建UserList.js,而狀態組建是通過react-redux的connect方法封裝UI元件UserList.js而得來的。
- 第二種,帶狀態的路由元件
// /pages/user/userList.js import { connect } from 'react-redux'; import UserList from '../../containers/user/UserList'; import { fetchUserListData } from '../../redux/actions/user'; UserList.getInitialProps = async (props) => { const { store, isServer } = props.ctx; if (store.getState().user.list.list.length === 0) { store.dispatch(fetchUserListData()); } return { isServer }; }; const mapStateToProps = state => ({ list: state.user.list.list, }); const mapDispatchToProps = dispatch => ({ fetchUserListData() { dispatch(fetchUserListData()); } }); export default connect(mapStateToProps, mapDispatchToProps)(UserList); 複製程式碼
簡單來說,就是在路由元件內把UI元件UserList.js通過connect變成了狀態元件。
個人推薦第一種方法,雖然寫起來稍微麻煩了一些,但是第二種方法完全是因為Next.js的特殊性才能實現的,當然,對於Next.js來說,第二種方式確實更簡單一些~
結束語
經歷了上面幾個部分的重構,整個基於Next.js的服務端渲染腳手架基本結構也就成型了。在搭建過程中還是遇到了很多坑的,不過也都一點點的踩過去了。希望對大家有些幫助,個人認為這個結構還是值得參考一下的~原本到這裡就可以結束系列文章了,不過我在使用過程又發現了一些坑,順便的Next.js還有一些內容我還沒碰過,就幫大家都踩一踩,下一節來一個其他內容的大雜燴~
ofollow,noindex">程式碼地址