Next.js踩坑入門系列
- (一) Hello Next.js
- (二) 新增Antd && CSS
- (三) 目錄重構&&再談路由
- (四) Next.js中期填坑
- (五) 引入狀態管理Redux
- (六) 再次重構目錄
- (七) 其他相關知識
上一節引入了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還有一些內容我還沒碰過,就幫大家都踩一踩,下一節來一個其他內容的大雜燴~