本文首發在個人我的博客:http://muyunyun.cn/posts/9bfb...css
使用React技術棧搭建一個後臺管理系統最初是爲了上手公司的業務,後來發現這個項目還能把平時遇到的有趣的demo給整合進去。此文嘗試對相關的技術棧以及如何在該項目中引人Redux進行分析。html
項目地址前端
小模塊展現:
node
redux在項目中的運用demo展現
react
├── build.js 項目打包後的文件 ├── config webpack配置文件 │ ├──... │ ├──webpack.config.dev.js 開發環境配置 │ ├──webpack.config.prod.js 生產環境配置 ├── node_modules node模塊目錄 ├── public │ └──index.html ├── scripts │ ├── build.js 打包項目文件 │ ├── start.js 啓動項目文件 │ └── test.js 測試項目文件 ├── src │ ├── client 匯聚(入口)目錄 │ ├── common 核心目錄 │ │ ├── actions redux中的action │ │ ├── components 通用功能組件 │ │ ├── container 通用樣式組件 │ │ ├── images │ │ ├── pages 頁面模塊 │ │ ├── reducers redux中的reducer │ │ ├── utils 工具類 │ │ │ ├── config.js 通用配置 │ │ │ ├── menu.js 菜單配置 │ │ │ └── ajax.js ajax模塊(往後用到) │ │ └── routes.js 前端路由 │ └── server 服務端目錄(往後用到) │ └── controller ├── .gitignore ├── package.json ├── README.md └── yarn.lock
項目的初始結構和構造緣由已羅列如上,因爲過些日子會引人ts,因此項目結構必然還會改動,但確定基於這基本雛形擴展的。webpack
下面對目錄結構做如下說明git
項目最初始是用 create-react-app 初始化的,create-react-app 是Facebook官方提供的 React 腳手架,也是業界最優秀的 React 應用開發工具之一;github
client 做爲入口目錄,到時候能夠把第三方中間件也放在此處;web
container 和 components 存放的都是 react 組件,區別以下表。可是我把和樣式有關的組件就放在container中,把和功能有關的模塊(好比本身分裝的表格組件、彈出輸入框組件等)就放到components中,若往後有須要,container 和 component 組件都是能夠在 Redux 數據流中的。ajax
container | component | |
---|---|---|
目的 | 如何工做(數據獲取,狀態更新) | 如何顯示(樣式,佈局) |
是否在 Redux 數據流中 | 是 | 否 |
讀取數據 | 從 Redux 獲取 state | 從 props 獲取數據 |
修改數據 | 向 Redux 派發 actions | 從 props 調用回調函數 |
實現方式 | 向react-redux生成 | 手寫 |
ajax 模塊到時候計劃用 fetch 封裝一個ajax,感受使用 fetch 仍是蠻便利的。
server 層就是做爲網關層,往後計劃用來寫 node 的。
雖然用到的技術棧衆多,可是本身也談不上熟練運用,多半是邊查API邊用的,因此只羅列些本身用相關的技術棧解決的點;
4月的時候 create-react-app 仍是基於 webpack(1.x) 構建的,5月27號升到了webpack(2.6),因而我也進行了 webpack 的版本升級。
babel-plugin-import 是一個用於按需加載組件代碼和樣式的 babel 插件,使用此插件後,在引人 antd 相應模塊就能實現按需引人,在config/webpack.config.dev.js 文件中做以下修改:
{ test: /\.(js|jsx)$/, include: paths.appSrc, loader: require.resolve('babel-loader'), options: { plugins: [ "transform-decorators-legacy", // 引人 ES7 的裝飾器 @ ['import', [{ libraryName: 'antd', style: true }]], ], cacheDirectory: true, }, },
首先引人 less-loader 來加載 less 樣式,同時修改 config/webpack.config.dev.js 文件
test: /\.less$/, use: [ require.resolve('style-loader'), require.resolve('css-loader'), { loader: require.resolve('postcss-loader'), options: { ident: 'postcss', //https://webpack.js.org/guides/migrating/#complex-options plugins: () => [ require('postcss-flexbugs-fixes'), autoprefixer({ browsers: [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9', // React doesn't support IE8 anyway ], flexbox: 'no-2009', }), ], }, }, { loader: require.resolve('less-loader'), options: { modifyVars: { "@primary-color": "#1DA57A" }, // 這裏利用了 less-loader 的 modifyVars 來進行主題配置, 變量和其餘配置方式能夠參考 [配置主題](https://user-gold-cdn.xitu.io/2017/6/15/e8ba356d7b10cec196d48159e41b6e6e) 文檔。 }, }, ], },
用到了 gh-pages ,使用 npm run deploy 一鍵發佈到本身的gh-pages上,姑且把gh-pages當成生產環境吧,因此在修改config/webpack.config.dev.js 文件的同時也要對 config/webpack.config.prod.js 做出如出一轍的修改。
alias: { 'react-native': 'react-native-web', components: path.resolve(__dirname, '..') + '/src/common/components', container: path.resolve(__dirname, '..') + '/src/common/container', images: path.resolve(__dirname, '..') + '/src/common/images', pages: path.resolve(__dirname, '..') + '/src/common/pages', utils: path.resolve(__dirname, '..') + '/src/common/utils', data: path.resolve(__dirname, '..') + '/src/server/data', actions: path.resolve(__dirname, '..') + '/src/common/actions', reducers: path.resolve(__dirname, '..') + '/src/common/reducers', },
配置了引用路徑的縮寫後,就能夠在任意地方如這樣引用,好比
import Table from 'components/table'
antd是(螞蟻金服體驗技術部)通過大量的項目實踐和總結,沉澱出的一箇中臺設計語言 Ant Design,使用者包括螞蟻金服、阿里巴巴、口碑、美團、滴滴等一系列知名公司,並且我從他們的設計理念也學到了不少關於UI、UX的知識。
該項目採用的是antd最新的版本2.10.0,因爲2.x的版本和1.x的版本仍是相差蠻大的,以前參考的項目(基於1.x)改起來太費勁,因此在組件那塊就乾脆本身從新封裝了一遍。這部分知識點建議多看文檔,官方更新仍是很是勤快的。
react-router 4.x和2.x的差別又是特別的大,召喚文檔,網上基本上都仍是2.x的教程,看過文檔以後,反正簡而言之其就是要讓使用者更容易上手。印象最深的是之前嵌套路由寫法在4.x中寫到同層了。以下示例他們的效果是相同的。
2.x:
<Route path="/" component={App}> <Route path="/aaaa" component={AAAA} /> <Route path="/bbbb" component={BBBB} /> </Route>
4.x:
<Route path="/" component={App} /> <Route path="/aaaa" component={AAAA} /> <Route path="/bbbb" component={BBBB} />
fetch 使用比較簡單,基本的 promise 用法以下
fetch(url).then(response => response.json()) .then(data => console.log(data)) .catch(e => console.log("Oops, error", e))
此外還能這樣用
try { let response = await fetch(url); let data = await response.json(); console.log(data); } catch(e) { console.log("Oops, error", e); }
可是其簡潔的特色是爲了讓咱們能夠自定義其擴展,仍是其自己就還不完善呢?我在調用 JSONP 的請求時,發現其不支持對 JSONP 的調用,所幸社區仍是很給力地找到了 fetch-jsonp 這個模塊,實現了對百度音樂接口調用。fetch-jsonp使用也和 fetch 相似,代碼以下
fetchJsonp(url,{method: 'GET'}) .then((res) =>res.json()) .then((data) => {})
使用了redux也已經有段時日了,我對redux的定義就是更好的管理組件的狀態,一旦應用的邏輯複雜起來,各類組件狀態、界面耦合起來,就容易出岔子,redux就是爲了解決這個而誕生的,讓咱們能夠更多地關注UI層,而下降對狀態的關注。
畫了一幅比較簡陋的圖來講明 redux 的大體流程,假設首先經過鼠標點擊頁面上的按鈕觸發了一個行爲(action),這時咱們叫了一輛出租車 dispatch() 將這個 action 帶到了終點站 store。這時候 store 就會經過 reducer 函數返回一個新的狀態 state,從而改變 UI 顯示。以前也寫了篇深刻Redux架構
下面經過把 代辦事項 這個demo運用到後臺管理系統中來說解 Redux 在其中的運用。
首先,在入口目錄建立 store
const store = createStore(rootReducer) ReactDOM.render( <Provider store={store}> { routes } </Provider>, document.getElementById('root') );
接着,我使用了 redux-actions 這個模塊。使用 redux-actions 的好處是能簡化大量對 action 的聲明,以及能簡化 reducer 的寫法。
代辦事項的 actions 文件片斷(拿展現所有任務、已完成任務、未完成任務的 action 舉例):
import { createAction } from 'redux-actions' export const setVisibility = createAction('SET_VISIBILITY')
沒使用 redux-actions 時,actions 寫法以下,可看出着實麻煩了很多,
export const setVisibility = (filter) => { return { type: "SET_VISIBILITY", filter } }
相應的代辦事項的 reducers 文件片斷:
export const setVisibility = handleActions({ 'SET_VISIBILITY'(state, action) { return { ...state, ...action.payload} } }, 'SHOW_ALL')
使用 redux-actions 後,只要進行以下調用,reducers文件裏的SET_VISIBILITY
的 action 就能捕獲到SHOW_ALL
這個狀態。
import { setVisibility } from 'actions/todoList' @connect( (state) => ({ setVisibility: state.setVisibility, // 這個 setVisibility 是取自 reducers 的 }) ) dispatch(this.props.dispatch(setVisibility('SHOW_ALL')))
connect 來自 react-redux,這裏的 @ 是 ES7裏的裝飾器的用法,使用它以後又能減小很多的代碼量,原來還要寫 mapStateToProps
、mapDispatchToProps
。
計劃在該項目把平時工做、學習中遇到的react案例抽離成demo展示出來,因此之後還會多出一些模塊。另外過段時間會在該項目中引人 typescript,若是還有精力的話,能夠在這個項目上折騰下網關層。喜歡這個項目的話,點我 Star。