一、開發前準備css
1.1 技術選型前端
1.2 總體設計node
1.3 構建開發mysql
背景:react
須要開發一個系統,讓用戶對角色進行投票,最後輸出統計結果,投票採用兩兩對比,用戶在喜好的角色上點擊便可進行投票,而且能夠輸出投票統計結果;用戶能夠查看角色信息詳情,新增角色信息,並未對用戶的權限做過多控制,全部用戶能夠新增角色和投票。jquery
技術選型:git
投票系統的後臺邏輯比較簡單,無非是增刪改查操做,相比之下IO的使用比較多,須要和前端進行較多的交互,呈現出高IO低計算的需求,node及react成爲適合的技術選型web
總體設計:sql
採用node做web服務器,考慮這是小demo,mysql做數據服務器足夠了,前端頁面爲了增長交互性和給用戶更好的體驗,採用SPA(單頁面應用),前端採用react+react-router,react只是ui的框架,對於數據的處理能夠配合alt(一種flux的實現),架構示意圖:數據庫
構建開發:
react生態中,因爲react框架自己完成的功能比較單一,須要配合其餘不少的庫或框架完成一套功能,而node具有的npm管理庫的能力,這與react的開發需求正好匹配,在開發前須要將運行所依賴的庫以及打包或開發所依賴的庫加入package.json中去;
另外,一些純前端的庫文件,如bootstrap、jquery等,可使用客戶端的包管理軟件bower進行管理,文件依賴在根目錄下的bower.json中定義,下載路徑默認是根目錄下的bower_components,在具有git環境下執行bower install;
爲了減少網絡開銷,js及css須要經過gulp工具各自合併,js文件經過gulp(browserify)構建,多個文件合併成一個,減少網絡開銷;browserify經過main.js爲入口,將整個依賴樹串起來,將整個業務js代碼打包成bundle.js;css文件經過gulp(less)構建,在main.less中定義
gulp打包步驟:
一、將客戶端的js庫(經過bower工具管理)打成一個文件,gulp.src表示源文件路徑,pipe表示流處理管道,最後合併到public/js/vendor.js
二、客戶端依賴的第三方庫(經過npm管理),打成一個文件
三、將業務文件打包,以main.js做爲打包入口,去除全部第三方依賴,而且經過babel轉換至ES5語法,打包至public/js/bundle.js
四、對業務代碼的變化進行監控,當代碼改變時,自動執行第三部的browserrify任務
五、對css文件打包,而且進行監控
技術點:
一、工程目錄結構,採用node+react開發的模式,目錄結構能夠按下面進行設置
root
---------app 先後端渲染採用同一套代碼,組件代碼都放在這個目錄下
---------components 組件定義
---------actions redux模式下的組件對應的action
---------stores redux模式下組件對應的store
---------stylesheets 外部樣式文件,react的樣式仍是須要單獨定義
----------bower_components 客戶端依賴的js庫,經過bower管理
----------models 數據庫表模型定義文件
----------node_modules 經過npm管理的庫文件目錄
----------public 客戶端引用的資源文件目錄,包括基於app目錄打包生產的js,基於app/stylesheets下的less生成的css,圖片
----------views 客戶端頁面文件
下面是文件
-----------bower.json bower工具配置文件,下載後的文件默認安裝在項目根目錄下的bower_components目錄
-----------config.js 數據庫鏈接信息配置文件
-----------gulpfile.js gulp工具打包步驟配置文件
-----------package.json 管理npm安裝包
-----------server.js node服務端運行文件
二、flux 數據單向流動模式,能同時運行在客戶端及node端
數據只能單向流動,最終view的改變只能由store的改變觸發,而action能夠在組件的代碼裏調用
在alt框架下,每一個組件擁有一個store及action文件,dispatcher不需過多關注
action一般完成邏輯編排和調用,並根據調用結果產生相應的action,這些action能被配套的store監聽.
須要引入alt對象,經過generateActions方法定義action,addCharacter對外暴露
store定義state的集合,監聽action,根據不一樣action完成state的更新,store時單例對象,若是採用了服務端渲染,在node啓動時,執行到import XXstore時就會初始化,客戶端在加載js時,執行到import XXstore時,初始化
須要引入alt對象及對應action,經過構造函數定義state,on+action名 構成的方法,監聽action
組件代碼中,構造函數中通常要調用getState獲取store初始狀態,而store的監聽與取消監聽在生命週期的componentDidMount及componentWillUnmount階段進行
下面是本身的思考:服務端渲染的狀況下,renderToString函數會執行組件的可視化階段,即render以前(包括render),在瀏覽器端執行剩下的生命週期便可,爲了保持store的一致,初始化階段到render之間不該該有store的改變
三、react-router 路由,能同時運行在客戶端及node端
單頁應用的場景下須要使用react-router,瀏覽器攔截請求,基於react計算出須要從新渲染的dom,對變化的部分進行渲染,這個過程不會向服務端發出頁面請求,跳轉過程當中變化的組件會mount與unmount,而且瀏覽器的前進後退按鈕,也不會整個頁面從新加載,路由過程組件的store不會銷燬,只會解綁監聽,因此當瀏覽器後退到以前頁面時,store的狀態能保持。
如下是我本身的推測:react 在設計之初就考慮服務端與客戶端同構,便可以使用同一套代碼,服務端不單是傳統意義的web請求分發處理了,加上了服務端渲染的概念,將不少瀏覽器端乾的活搶去幹了。基於此,後續的react插件都支持服務端與客戶端的運行,服務端渲染通常在首頁加載,爲了提高用戶體驗而須要採用的技術,其餘時候採用客戶端單獨渲染就夠用了。
頁面跳轉使用react-router提供的<Link>標籤: 組件文件頭中import {Link} from 'react-router'; 跳轉的地方使用<Link to='/shame'>Hall of Shame</Link>, 使用Link標籤可以實現變化的dom刷新
典型代碼模塊:
路由文件route.js,定義了url與組件的匹配關係,這裏的App組件是整個應用的根組件,通常要將SPA的可變組件嵌套進去:
根組件app.js,注意可變組件的寫法:
服務端與客戶端使用的是同一套代碼,但路由入口不同,服務端在server.js中定義,考慮全部的頁面請求,都須要經過路由來得到,
如下是個人總結:對於SPA場景,須要使用react-router,服務端可斟酌使用router;而對於普通的應用,就不須要使用react-router了,能夠針對不一樣的url請求設置node中間件,路由到不一樣的靜態頁面文件,服務端渲染也可選擇是否使用。
客戶端路由入口,須要經過構建工具打包至bundle.js中: