最近這些年,隨着前端應用技術日新月異,產生了不少新的前端框架,固然也引入了數不勝數的前端技術概念,前端不在是早期Web Form的拖拉處理方式,也再也不是Ajax+HTML那麼簡單,隨着前端技術的發展,前端的JS愈來愈重要,也愈來愈複雜,而爲了開發的方便,引入了不少能夠對JS+CSS進行編譯的框架,而在發佈的時候按需編譯處理,從而加強了整個前端的開發過程,這些前端的技術包括AngularJS、React、Vue等等,這些前端技術應用框架又囊括了不少相關的技術,包括了MVVM(Model-View-ViewModel)、ES六、Babel、dva、umi、less等技術或概念。前端技術越滾越大,範圍也愈來愈廣,大有突飛猛進的感受。html
記得在上大學時候,開始玩asp的年代,前端和後端糅合一塊兒的困境;也曾記得WebForm開發的樂趣和無奈,快捷可是很醜很笨重;而如今還在繼續作着Ajax + HTML的這種前端的處理,痛並快樂着。技術老是一步步的推動則,可是眼光一旦聚焦在某個技術範疇,日月如梭,擡頭間很快就會發現世界又多了新的前端技術,從開始的猶豫和不確信的停留這段時間後,發現整個前端的世界也已經漸成格局,包括Angular、React、Vue等技術應用已經日趨成熟,並且擁有着龐大的擁躉羣體,也有着豐富的資源可供學習和了解。前端
下面是Angular、React、Vue幾個技術框架的一些介紹。react
AngularJS誕生於2009年,由Misko Hevery 等人建立,後爲Google所收購。是一款優秀的前端JS框架,已經被用於Google的多款產品當中。AngularJS有着諸多特性,最爲核心的是:MVC(Model–view–controller)、模塊化、自動化雙向數據綁定、語義化標籤、依賴注入等等。Angular開發在全球開發人員中普遍流行,並被谷歌,福布斯,WhatsApp,Instagram,healthcare.gov和許多財富500強公司等大型組織使用。git
React 起源於 Facebook 的內部項目,由於該公司對市場上全部 JavaScript MVC 框架,都不滿意,就決定本身寫一套,用來架設 Instagram 的網站。作出來之後,發現這套東西很好用,就在2013年5月開源了。 因爲 React 的設計思想極其獨特,屬於革命性創新,性能出衆,代碼邏輯卻很是簡單。因此,愈來愈多的人開始關注和使用,認爲它多是未來 Web 開發的主流工具。es6
Vue.js是討論最多且發展最快的JavaScript框架之一。它由前谷歌員工Evan You建立,他在擔任Google員工時曾在Angular工做過。您能夠認爲它是成功的,由於它可以使用HTML,CSS和JavaScript構建有吸引力的UI。github
這些技術各有優勢,很難片面的說明誰優誰劣,它們都各自有本身的生存土壤和大批的擁躉,而我開始選型作前端技術更新的時候,主要看中的是阿里巴巴的Ant-Design開發框架,這個它是使用了React的技術框架,所以也就天然而然的研究學習起React和Ant-Design來,雖然以前對前端的一些技術有所涉獵,可是真正等你想要進入Ant-Design的開發大門的時候,仍是感受本身像進入了一個前端技術的大觀園,一個個新概念接踵而來,一種種代碼的寫法迎面衝擊,教程看了幾遍仍是一頭霧水,真的開始懷疑人生了,不過學習新技術仍是須要不少平靜的心態,調整好,一步一個腳印相信仍是有所斬獲的,偶爾看到阮一峯的大牛介紹在學習研究React的時候,也曾花了幾個月的時候,雖然他的高度難以看齊,可是學習的韌勁和毅力,是值得咱們學習的。學習新的東西,從技術角度,能夠知足好奇心,提升技術水平;從職業角度,有利於求職和晉升,有利於參與潛力大的項目(摘自阮一峯筆記)。web
接觸一些新的東西,就必然須要投入精力來學習掌握。對於學習Ant-Desin,雖然這個框架自己提供了不少教程介紹,可是咱們一些技術點,仍是須要更細節的學習,首推仍是阮一峯的技術日誌吧。redux
二、React 入門實例教程 api
五、Redux 入門教程(三):React-Redux 的用法
下面有些內容在學習的時候,掌握的不是很好,摘錄並做爲一個回顧吧。
模塊的 Import 和 Export
import
用於引入模塊,export
用於導出模塊。
// 引入所有 import dva from 'dva'; // 引入部分 import { connect } from 'dva'; import { Link, Route } from 'dva/router'; // 引入所有並做爲 github 對象 import * as github from './services/github'; // 導出默認 export default App; // 部分導出,需 import { App } from './file'; 引入 export class App extend Component {};
析構賦值
析構賦值讓咱們從 Object 或 Array 裏取部分數據存爲變量。
// 對象 const user = { name: 'guanguan', age: 2 }; const { name, age } = user; console.log(`${name} : ${age}`); // guanguan : 2 // 數組 const arr = [1, 2]; const [foo, bar] = arr; console.log(foo); // 1
咱們也能夠析構傳入的函數參數。
const add = (state, { payload }) => { return state.concat(payload); }; //析構時還能夠配 alias,讓代碼更具備語義 const add = (state, { payload: todo }) => { return state.concat(todo); };
對象展開運算符(Object Spread Operator)
//可用於組裝數組。 const todos = ['Learn dva']; [...todos, 'Learn antd']; // ['Learn dva', 'Learn antd'] //也可用於獲取數組的部分項。 const arr = ['a', 'b', 'c']; const [first, ...rest] = arr; rest; // ['b', 'c'] // With ignore const [first, , ...rest] = arr; rest; // ['c'] //還可收集函數參數爲數組。 function directions(first, ...rest) { console.log(rest); } directions('a', 'b', 'c'); // ['b', 'c']; //代替 apply。 function foo(x, y, z) {} const args = [1,2,3]; // 下面兩句效果相同 foo.apply(null, args); foo(...args); //對於 Object 而言,用於組合成新的 Object const foo = { a: 1, b: 2, }; const bar = { b: 3, c: 2, }; const d = 4; const ret = { ...foo, ...bar, d }; // { a:1, b:3, c:2, d:4 }
propTypes
JavaScript 是弱類型語言,因此請儘可能聲明 propTypes 對 props 進行校驗,以減小沒必要要的問題。
function App(props) { return <div>{props.name}</div>; } App.propTypes = { name: React.PropTypes.string.isRequired, };
內置的 prop type 有:
DVA數據流向
數據的改變發生一般是經過用戶交互行爲或者瀏覽器行爲(如路由跳轉等)觸發的,當此類行爲會改變數據的時候能夠經過 dispatch 發起一個 action,若是是同步行爲會直接經過 Reducers 改變 State ,若是是異步行爲(反作用)會先觸發 Effects 而後流向 Reducers 最終改變 State。
Reducer和effects
reducer 是一個函數,接受 state 和 action,返回老的或新的 state 。即:(state, action) => state
app.model({ namespace: 'todos', state: [], reducers: { add(state, { payload: todo }) { return state.concat(todo); }, remove(state, { payload: id }) { return state.filter(todo => todo.id !== id); }, update(state, { payload: updatedTodo }) { return state.map(todo => { if (todo.id === updatedTodo.id) { return { ...todo, ...updatedTodo }; } else { return todo; } }); }, }, };
建議最多一層嵌套,以保持 state 的扁平化,深層嵌套會讓 reducer 很難寫和難以維護。
app.model({ namespace: 'app', state: { todos: [], loading: false, }, reducers: { add(state, { payload: todo }) { const todos = state.todos.concat(todo); return { ...state, todos }; }, }, });
effects示例
app.model({ namespace: 'todos', effects: { *addRemote({ payload: todo }, { put, call }) { yield call(addTodo, todo); yield put({ type: 'add', payload: todo }); }, }, });
put用於觸發 action,call用於調用異步邏輯,支持 promise。
異步請求
異步請求基於 whatwg-fetch,API 詳見:https://github.com/github/fetch
GET 和 POST
import request from '../util/request'; // GET request('/api/todos'); // POST request('/api/todos', { method: 'POST', body: JSON.stringify({ a: 1 }), });
統一錯誤處理
假如約定後臺返回如下格式時,作統一的錯誤處理。
{ status: 'error', message: '', }
編輯 utils/request.js
,加入如下中間件:
function parseErrorMessage({ data }) { const { status, message } = data; if (status === 'error') { throw new Error(message); } return { data }; }
而後,這類錯誤就會走到 onError
hook 裏。
Subscription
subscriptions
是訂閱,用於訂閱一個數據源,而後根據須要 dispatch 相應的 action。數據源能夠是當前的時間、服務器的 websocket 鏈接、keyboard 輸入、geolocation 變化、history 路由變化等等。格式爲 ({ dispatch, history }) => unsubscribe
。
異步數據初始化
好比:當用戶進入 /users
頁面時,觸發 action users/fetch
加載用戶數據。
app.model({ subscriptions: { setup({ dispatch, history }) { history.listen(({ pathname }) => { if (pathname === '/users') { dispatch({ type: 'users/fetch', }); } }); }, }, });
connect 的使用
connect 方法返回的也是一個 React 組件,一般稱爲容器組件。由於它是原始 UI 組件的容器,即在外面包了一層 State。
connect 方法傳入的第一個參數是 mapStateToProps 函數,該函數須要返回一個對象,用於創建 State 到 Props 的映射關係。
簡而言之,connect接收一個函數,返回一個函數。
第一個函數會注入所有的models,你須要返回一個新的對象,挑選該組件所須要的models。
export default connect(({ user, login, global = {}, loading }) => ({ currentUser: user.currentUser, collapsed: global.collapsed, fetchingNotices: loading.effects['global/fetchNotices'], notices: global.notices }))(BasicLayout); // 簡化版 export default connect( ({ user, login, global = {}, loading }) => { return { currentUser: user.currentUser, collapsed: global.collapsed, fetchingNotices: loading.effects['global/fetchNotices'], notices: global.notices } } )(BasicLayout);
@connect的使用
其實只是connect的裝飾器、語法糖罷了。
// 將 model 和 component 串聯起來 export default connect(({ user, login, global = {}, loading }) => ({ currentUser: user.currentUser, collapsed: global.collapsed, fetchingNotices: loading.effects['global/fetchNotices'], notices: global.notices, menuData: login.menuData, redirectData: login.redirectData, }))(BasicLayout);
// 改成這樣(export 的再也不是connect,而是class組件自己。),也是能夠執行的,但要注意@connect必須放在export default class前面: // 將 model 和 component 串聯起來 @connect(({ user, login, global = {}, loading }) => ({ currentUser: user.currentUser, collapsed: global.collapsed, fetchingNotices: loading.effects['global/fetchNotices'], notices: global.notices, menuData: login.menuData, redirectData: login.redirectData, })) export default class BasicLayout extends React.PureComponent { // ... }
以上部份內容摘自 https://blog.csdn.net/zhangrui_web/article/details/79651812
這款基於React開發的UI框架,界面很是簡潔美觀,是阿里巴巴旗下螞蟻金融服務集團(旗下擁有支付寶、餘額寶等產品)所設計的一個前端UI組件庫。目前支持了React, 而且有一個對Vue支持的測試版本。
學習和使用Ant-Design,咱們可使用VSCode來對項目代碼進行維護和編輯,這樣能夠在Mac和Window環境一樣的開發體驗和操做模式,很是方便。
若是須要掌握Ant-Design框架,咱們須要瞭解model,namespace,connect,dispatch,action,reducer ,effect這些概念。
DVA 的 model 對象有幾個基本的屬性介紹。
namespace
:model 的命名空間,只能用字符串。一個大型應用可能包含多個 model,經過namespace
區分。state
:當前 model 狀態的初始值,表示當前狀態。reducers
:用於處理同步操做,能夠修改 state
,由 action
觸發。reducer 是一個純函數,它接受當前的 state 及一個 action 對象。action 對象裏面能夠包含數據體(payload)做爲入參,須要返回一個新的 state。effects
:用於處理異步操做(例如:與服務端交互)和業務邏輯,也是由 action 觸發。可是,它不能夠修改 state,要經過觸發 action 調用 reducer 實現對 state 的間接操做。action
:action 就是一個普通 JavaScript 對象,是 reducers 及 effects 的觸發器,形如{ type: 'add', payload: todo }
,經過 type 屬性能夠匹配到具體某個 reducer 或者 effect,payload 屬性則是數據體,用於傳送給 reducer 或 effect。總體的數據流向見下圖:
在Reducer裏面,不要修改傳入的 state
。 使用 Object.assign()
新建了一個副本。不能這樣使用 Object.assign(state, { visibilityFilter: action.filter })
,由於它會改變第一個參數的值。你必須把第一個參數設置爲空對象。
function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }) default: return state } }
或者使用使用對象展開運算符(Object Spread Operator)來處理,從而使用 { ...state, ...newState }
達到相同的目的。
reducers: { save(state, action) { return { ...state, ...action.payload, }; }, },
在 default
狀況下返回舊的 state
。遇到未知的 action 時,必定要返回舊的 state
。
每一個 reducer 只負責管理全局 state 中它負責的一部分。每一個 reducer 的 state
參數都不一樣,分別對應它管理的那部分 state 數據。
下面兩種合成 reducer 方法徹底等價:
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
})
function reducer(state = {}, action) { return { a: doSomethingWithA(state.a, action), b: processB(state.b, action), c: c(state.c, action) } }
dva封裝了redux,減小不少重複代碼好比action reducers 常量等,dva全部的redux操做是放在models目錄下,經過namespace做爲key,標識不一樣的模塊state,能夠給state設置初始數據。
reducers跟傳統的react-redux寫法一致,全部的操做放在reducers對象內
Effect 被稱爲反作用,在咱們的應用中,最多見的就是異步操做,Effects
的最終流向是經過 Reducers
改變 State
。
其中上面的effects裏面,call, put實際上是saga的寫法,dva集成了saga,能夠參考上圖中的saga內容
DVA 首先是一個基於 redux 和 redux-saga 的數據流方案,而後爲了簡化開發體驗,DVA 還額外內置了 react-router 和 fetch,因此也能夠理解爲一個輕量級的應用框架。
DVA 是基於現有應用架構 (redux + react-router + redux-saga 等)的一層輕量封裝,沒有引入任何新概念,所有代碼不到 100 行。
在Ant-Design的Pages/.umi目錄裏面,有一個initDva.js文件,就是用來統一批量處理 DVA 的引入的,以下所示。
在有 DVA 以前,咱們一般會建立 sagas/products.js
, reducers/products.js
和 actions/products.js
,而後在這些文件之間來回切換。
有了 DVA 後,它最核心的是提供了 app.model
方法,用於把 reducer, initialState, action, saga 封裝到一塊兒,這樣咱們在書寫代碼的時候,把它主要內容,和加載分離出來。若是創建的Model比較多,每次開始的時候須要加入這一句好像也是挺麻煩的,若是能夠自動把這個model批量加入,應該會更好吧,不過不知道是基於什麼考量。