平時開發單頁項目應用基於vue,目前另外兩個比較熱的庫還有angular和react,angular 1系列用過,進入公司後因爲基於vue技術棧就沒在關注了。
一直在關注react,目的不是學習用法,只是爲了拓展本身的視野和思惟,經過了解一些使用上的差別性,來進一步的思考其底層設計的思想。css
在具體業務邏輯開發前,咱們首先要作的是搭建項目骨架,vue的話可使用vue-cli,經過腳手架產生的配置徹底暴露出來,咱們能夠靈活的修改配置來定製化需求。
我經常使用幾個配置以下html
build時assetsPublicPath會修改爲相對引入,或者配置成公共前綴,方便測試 dev時proxyTable代理一些接口,聯調用,本身測試話就直接用mock數據服務 關閉devtool,去除contenthash,chunkhash,html的minify,添加externals,定製化一些eslint……等等 其它也有一些不通用改動,上面是每一個項目都通用的配置
至於react可使用create-react-app架手架,而後就直接可使用create-react-app建立項目了,默認隱藏配置,定製化配置能夠直接npm run eject。須要注意點就是使用create-react-app建立比較慢,須要作以下設置vue
npm config set registry https://registry.npm.taobao.org
其實自定義配置直接在配置依賴包裏也能夠改動,不過這樣不太好。其次腳手架建立項目最好不要在已有git目錄下載建立,否則使用npm run eject會報錯,此時用空目錄下建立便可。
不管是哪一個腳手架經常使用的配置,都是基於webpack核心生態圈構建,因此核心重點就是webpack用的熟練的話,不管使用哪一個自定義化配置都不成問題。react
vue稍微複雜些單頁會基於vue+vuex+vue-router,react棧是react+redux+react-router。
不一樣點是vue組件是(html+css+js),對開發友好,上手容易。react一切都是js,特別的靈活,經過在render中利用純js邏輯控制渲染輸出模板。下面是基於react的一個示例。webpack
render() { let name = this.state.flag ? 'true':'false' return ( <ul> {this.props.items.map(item => ( <li key={item.id}>{item.text}</li> ))} {name} </ul> ); }
vue的語法糖可讓咱們在表單上輕鬆的實現雙向綁定,而react是純粹的基於UI=render(data)的理念。vue利用es5的set,get機制收集依賴,能詳細的定位修改元素,react每次setState對組件構造函數中私有屬性進行修改時,組件都會更新,除非你在shouldComponentUpdate加入一些邏輯處理。另外vue提供的api多,有不少好用又方便的指令,可是具備兩面性,而react核心概念少,js用的溜,上手挺容易的。git
不管是vue仍是react都支持組件私有屬性;組件之間prop,組件之間簡單關數據系修改的話,可使用事件的方式,vue此時又提供了個語法糖sync,吼吼,其它的話沒啥差別。web
比較麻煩的一點就是複雜網狀組件之間數據流動時處理,此時就須要合理組織數據了,否則維護,調試就是一個大坑,事件方式就不適合了,此時就要說到vuex和redux了,vuex的getter獲取state中數據,映射到組件data屬性上,Mutation同步commit修改數據,Action中dispatch可同步or異步修改數據,核心是單一狀態樹,經過設計層層方法最後達到修改數據的目的就是爲了更好的管理,檢測數據的流動。redux由於平時用的少,因此此刻我要描述的詳細些,以作備忘。算法
import {createStore, applyMiddleware, compose} from 'redux' import thunk from 'redux-thunk' import {Provider} from 'react-redux' const store = createStore(counter, compose( applyMiddleware(thunk), window.devToolsExtension?window.devToolsExtension(): f => f )) ReactDOM.render( <Provider store={store}> <JSDT/> </Provider>, document.getElementById('root') );
瞭解背後原理,可讓咱們更靈活的控制代碼,下面開始詳細的分析。
執行createStore,提供一個狀態樹的初始化環境,返回一個對象,其中包含一些閉包函數,引用createStore初始化環境中中的各類函數和變量,例如dispatch(派發action),getState(獲取只讀狀態樹上的值),subscribe(訂閱數據改變)等等,其中spring
dispatch({ type: ActionTypes.INIT })(源碼:248)
此代碼的目的是建立store的時候,給reduce一個默認值,初始化currentState值,方便初次getState調用。vue-router
applyMiddleware中間件機制,能夠在處理store先後加一些通用處理,其它例如express,koa,springMVC這些框架中都有這種思想,實現方式不一樣,目的都同樣,解耦,可插拔效果,便於維護。
而rudux中applyMiddleware實現原理是利用高階函數compose,經過reduce將多個函數組合成一個可執行執行函數,關鍵步驟代碼以下所示。
//applyMiddleware.js chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
//compose.js funcs.reduce((a, b) => (...args) => a(b(...args)))
thunk 至於這個就是用來方便作異步處理的,是一個高階函數中間件,以下所示,通常action返回的都是一個行爲描述對象,可是這個在你對store進行處理前加了一層邏輯判斷,以便咱們在組件上統一的方式寫dispatch相關的代碼。
if (typeof action === 'function') { return action(dispatch, getState, extraArgument); }
devToolsExtension //開啓調試工具,沒有vue方便,不能自動檢測
Provider提供一個上下文環境,讓一個樹上的全部組件都能訪問同一個對象。必要前提條件是添加加childContextTypes和getChildContext。
爲了更好的體驗,通常咱們會採起一些措施,下面總結一下針對vue和react的優化措施。
重單頁應用,在路由中咱們能夠異步加載組件,雖然二者都支持,原理相似,可是vue使用極其方便,以下所示
const My = () => import('../components/My.vue')
有一點須要注意的就是須要配置下assetsPublicPath,這樣打包後的url中是全路徑,不然按照相對路徑處理容易出問題;相對而言react還要用模板代碼包裝下組件,這一點很差,不過將來react將來會開啓異步渲染組件的支持,這一點很贊。
vue和react都是基於dom diff更新差別元素。vue中,咱們操做的data數據是vue封裝處理過,修改數據時,vue會將數據初始化時收集的相關依賴元素進行更新,而react每次setState更新數據針對的是組件,爲了優化,組件設計的時候儘可能細粒度,尤爲是react當中的展現類組件。
由於二者使用的是針對web頁面狀況優化過的dom diff算法,以使複雜度下降爲O(n),因此有一些默認前提,理解並按照默認diff規則才能使代碼達到最優,好比說,保持根節點一致;一個dom父節點下有多個子節點並列時,給子節點添加key,防止對父節點使用insertBefore插入子節點這種狀況等等。
陸陸續續的學習過程當中,將本身的想法本身總結下來。
說明,文中的總結基於下面這些版本,vue ^2.4.2react 16.0.0-rc.2redux 3.7.2react-router 4.2