上一節引入了redux以及使用redux-saga來進行異步函數的處理,而上一節的目錄只是簡單的引入redux而已,redux但是至關龐大和複雜的,而且也算是我的習慣了吧。action分離,reducer分離,狀態組件container等等。我喜歡把這些東西劃分的清清楚楚,這樣一個項目維護起來纔會方便~這一節就從頭至尾來進行目錄的劃分,由於Next.js和本來的React SPA項目有必定的區別,主要體如今路由部分,因此我也是按照本身的理解和舒服的方式進行目錄重構!react
// ================ 目錄結構 ================== //
——————
| -- 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樹很大,這種結構很是的清晰~git
其實actions徹底能夠放在一個文件裏使用,不過項目龐大了之後維護起來仍是有些麻煩的,因此按照組件化思想,每個組件對應一個action,或者每個大功能塊對應一個action仍是比較合理的。github
-- redux
| -- actions
| -- home.js // 處理首頁action
| -- user.js // 處理與用戶有關action
| ... // 其餘action
複製代碼
reducer部分確定是要分離的,由於redux的官方爲咱們提供combineReducer這個API就是合併不一樣組件的reducer的,因此能夠理解爲redux的reducer推薦就是根據組件進行劃分的~就如同整個應用只有一個狀態樹同樣,每個reducer負責處理樹的不一樣枝葉派發出來的action。具體reducer內容仍是去看redux官方文檔吧。json
-- redux
| -- reducers
| -- home // 首頁部分reducer
| -- user // 用戶相關reducer
| ... // 其餘reducer
| index.js // rootReducer,由combineReducer生成
複製代碼
這裏須要特別說明一下~~~因爲Next.js的特殊緣由,其實已經作到了UI組件的分離,其實這一層container徹底能夠由pages文件夾代替,也就是能夠用路由組件經過react-redux的connect函數封裝一下,這樣就變成了一個帶狀態的路由組件,不知道你們明不明白我說的話。。。下面是兩種方法,你們按需本身採起,以UserList組件爲例:redux
// /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變成了狀態組件。api
我的推薦第一種方法,雖然寫起來稍微麻煩了一些,可是第二種方法徹底是由於Next.js的特殊性才能實現的,固然,對於Next.js來講,第二種方式確實更簡單一些~bash
經歷了上面幾個部分的重構,整個基於Next.js的服務端渲染腳手架基本結構也就成型了。在搭建過程當中仍是遇到了不少坑的,不過也都一點點的踩過去了。但願對你們有些幫助,我的認爲這個結構仍是值得參考一下的~本來到這裏就能夠結束系列文章了,不過我在使用過程又發現了一些坑,順便的Next.js還有一些內容我還沒碰過,就幫你們都踩一踩,下一節來一個其餘內容的大雜燴~babel
代碼地址antd