嚴格的單向數據流是 Redux 架構的設計核心,使用 Redux 的一個好處就是讓 state 的變化過程變的可預知和透明。javascript
Redux約定使用普通對象object tree來描述應用的 state ,若是想更新 state 中的數據,須要先發起一個 action請求來對更改進行描述,而後調用 reducer函數執行state更改。java
Store 就是用來維持應用全部的 state 的一個對象。react
getState()
git
返回應用當前的 state 樹;github
dispatch(action : object)
:json
分發 action 改變 store;redux
subscribe(listener : Function)
: 數組
註冊監聽器, 每當 dispatch action 的時候就會執行; state 樹中的一部分可能已經變化, 能夠在回調函數裏調用 getState()
來拿到當前 state。promise
replaceReducer(nextReducer : Function)
:架構
用 nextReducer 替換當前 store 的 reducer。在須要實現代碼分隔,並且須要當即加載一些 reducer 的時候纔可能會用到它,在實現 Redux 熱加載機制的時候也可能會用到。
建立一個 Redux store 來以存放應用中全部的 state:createStore(reducer, [preloadedState], enhancer)
參數
reducer(): Function
接收兩個參數,分別是當前的 state 樹和要處理的action,返回新的state 樹。
preloadedState: any
初始化state。 若是使用 combineReducers 建立 reducer,它必須是一個普通對象,與傳入的 keys 保持一樣的結構;不然能夠自由傳入任何 reducer 可理解的內容。
enhancer: Function
Store enhancer 是一個組合 store creator 的高階函數,返回一個新的強化過的 store creator。
返回值
Store
: 保存了應用全部 state 的對象。
栗子
import React from 'react' import { createStore } from 'redux' import reducer from './reducers' const store = createStore(reducer);
Action 是把數據從應用傳到 store 的有效載荷。它是 store 數據的惟一來源。action 內必須使用一個字符串類型的 type
字段來表示將要執行的動做。
type
會被定義成字符串常量。{ type: ADD_TODO, text: 'Build my first Redux app' }
Action Creator 就是生成 action 的方法。
function fetchPosts(url) { return { type: FETCH_POSTS, url } }
store 裏直接經過 store.dispatch()
調用 action,可是多數狀況下會使用 react-redux 提供的 connect()
來調用。bindActionCreators()
能夠自動把多個 action 建立函數 綁定到 dispatch()
方法上。
一個約定俗成的作法是經過建立函數生成 action 對象,而不是在dispatch 的時候內聯生成action。
// 1. 內聯生成 action store.dispatch({ type: ADD_TODO, text: 'Build my first Redux app' }) // 2. Action Creator 生成 action function fetchPosts(url) { return { type: FETCH_POSTS, url } } store.dispatch(fetchPosts(url))
Redux 的應用程序中最多見的 state 結構是一個簡單的 JavaScript 對象,它最外層的每一個 key 中擁有特定域的數據。給這種 state 結構寫 reducer 的方式是分拆成多個 reducer,拆分以後的 reducer 都是相同的結構(state, action),而且每一個函數獨立負責管理該特定切片 state 的更新。多個拆分以後的 reducer 能夠響應一個 action,在須要的狀況下獨立的更新他們本身的切片 state,最後組合成新的 state。
function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }); default: return state; } }
這是一個高階 Reducer ,combineReducers
接收拆分以後的 reducer 函數組成的對象,而且建立出具備相同鍵對應狀態對象的Reducer函數。目前 combineReducers
只能處理普通的 JavaScript 對象。
若是沒有給 createStore
提供預加載 state,輸出 state 對象的 key 將由輸入的拆分以後 reducer 組成對象的 key 決定。
結合Immutable.js 使用
combineReducers 不解決 Immutable.js,Maps等構建的 state tree,也不會把其他部分的 state 做爲額外參數傳遞給 reducer 或者排列 reducer 的調用順序,它一樣不關心 reducer 如何工做。如今有大量提供相似功能的工具,例如 redux-immutable,這個第三方包實現了一個可以處理 Immutable Map 數據而非普通的 JavaScript 對象的 combineReducers
。
栗子
1.定義reducers
/** * reducers.js */ function info(state = {}, action) { switch (action.type) { case 'UPDATE_NAME': return { ...state, name: action.text }; case 'UPDATE_SCHOOL': return { ...state, school: action.text }; default: return state } } function age(state = {}, action) { switch (action.type) { case 'INCREMENT_AGE': return { ...state, age: state.age + 1 }; case 'DECREMENT_AGE': return { ...state, age: state.age - 1 } default: return state } } export { info, age };
2.建立store, 引入combineReducers
/** * App.js */ import { createStore, combineReducers } from 'redux' import { info, age } from './reducers.js' let store = createStore(combineReducers({ info, age }), { name: '', school: '', age: 0 }); console.log(store.getState()) // { // info: { name: '', school: '' }, // age: 0 // } store.dispatch({ type: 'UPDATE_NAME', text: 'Use Redux' }) console.log(store.getState()) // { // info: { name: 'Use Redux', school: '' }, // age: 0 // }
同步: Action 發出之後,Reducer 當即算出 State;
異步:Action 發出之後,過一段時間再執行 Reducer;
默認狀況下,createStore()
所建立的 Redux store 只支持同步數據流, dispatch
只能接收一個普通對象。怎麼才能在異步操做結束後Reducer自動執行呢?這時就須要使用中間件。
Redux middleware 提供的是 action 被髮起以後,到達 reducer 以前的擴展點,在每一個 action 對象 dispatch 出去以前,注入一個自定義的邏輯來解釋 action 對象。
中間件能夠進行日誌記錄、建立崩潰報告、調用異步接口或者路由等等;在applyMiddleware
方法裏把中間件做爲參數傳入。此方法是 Redux 的原生方法,做用是將全部中間件組成一個數組,依次執行。
applyMiddleware(...middleware)
參數
...middleware
遵循 Redux middleware API 的函數。每一個 middleware 接受 Store
的 dispatch
和 getState
函數做爲命名參數,並返回一個函數。該函數會被傳入被稱爲 next
的下一個 middleware 的 dispatch 方法,並返回一個接收 action 的新函數,這個函數能夠直接調用 next(action)
,或者在其餘須要的時刻調用,甚至根本不去調用它。調用鏈中最後一個 middleware 會接受真實的 store 的 dispatch
方法做爲 next
參數,並藉此結束調用鏈。因此,middleware 的函數簽名是 ({ getState, dispatch }) => next => action
。
返回值
(Function) :一個應用了 middleware 後的 store enhancer。這個 store enhancer 的簽名是 createStore => createStore
,可是最簡單的使用方法就是直接做爲最後一個 enhancer
參數傳遞給 createStore()
函數。
實現請求先後打日誌, 請求失敗處理異常的中間件:
import { createStore, combineReducers, applyMiddleware } from 'redux'; import reducers from './reducers' // 請求先後日誌記錄middleware const logger = store => next => action => { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result } // 請求異常記錄middleware const crashReporter = store => next => action => { try { return next(action) } catch (err) { console.error('Caught an exception!', err) Raven.captureException(err, { extra: { action, state: store.getState() } }) throw err } } // createStore引入本身建立的middleware const store = createStore( combineReducers(reducers), preloadedState, applyMiddleware(logger, crashReporter) )
從右到左來組合多個函數: compose(...functions)
compose(funcA, funcB, funcC)
形象爲 compose(funcA(funcB(funcC())))
參數
(arguments): 須要合成的多個函數。預計每一個函數都接收一個參數。它的返回值將做爲一個參數提供給它左邊的函數,以此類推
返回值
(Function): 從右到左把接收到的函數合成後的最終函數。
react-redux是使用redux開發react時使用的一個插件。react-redux提供了兩個重要的API:Provider、connect
。
<Provider>
API<Provider>
使組件層級中的 connect()
方法都可以得到 Redux store。
正常狀況下,你的根組件應該嵌套在 <Provider>
中才能使用 connect()
方法。若是不想把根組件嵌套在 <Provider>
中,你能夠把 store
做爲 props 傳遞到每個被 connect()
包裝的組件。
屬性
store
: 應用程序中惟一的 Redux store 對象;children: ReactElement
: 組件層級的根組件;栗子
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import App from './App'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
connect
API鏈接 React 組件與 Redux store。鏈接操做不會改變原來的組件類, 返回一個新的已與 Redux store 鏈接的組件類。connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
參數
mapStateToProps(state, [ownProps]): Function
stateProps。
mapStateToProps
函數若是定義了就會被調用;ownProps
,則該參數的值爲傳遞到組件的 props。只要組件接收新的 props,mapStateToProps
也會被調用。(例如,當父組件從新渲染子組件props改變,那麼 ownProps 參數,mapStateToProps 都會被從新計算)該函數必須返回一個純對象,這個對象會與組件的 props 合併。
mapDispatchToProps(dispatch, [ownProps]):(Object / Function)
dispatchProps。
dispatch
方法會將 action creator 的返回值做爲參數執行。這些屬性會被合併到組件的 props 中。dispatch
函數,返回值是一個對象。返回對象經過 dispatch
函數與 action creator 以某種方式綁定在一塊兒。mapDispatchToProps
,默認狀況下,dispatch
會注入到你的組件 props 中。ownProps
,該參數的值爲傳遞到組件的 props,並且只要組件接收到新 props,mapDispatchToProps
也會被調用。mergeProps(stateProps, dispatchProps, ownProps): Function]
props。
mapStateToProps()
與 mapDispatchToProps()
的執行結果和組件自身的 props
將傳入到這個回調函數中。(Object.assign({}, ownProps, stateProps, dispatchProps)
的結果。options: Object
若是指定這個參數,能夠定製 connect 的行爲;
pure = true
] (Boolean): 若是爲 true,connector 將執行 shouldComponentUpdate
而且淺對比 mergeProps
的結果,避免沒必要要的更新,前提是當前組件是一個「純」組件,它不依賴於任何的輸入或 state 而只依賴於 props 和 Redux store 的 state。默認值爲 true
。withRef = false
] (Boolean): 若是爲 true,connector 會保存一個對被包含的組件實例的引用,該引用經過 getWrappedInstance()
方法得到。默認值爲 false
。返回值
根據配置信息,返回一個注入了 state 和 action creator 的 React 組件。
redux-thunk是redux解決異步的中間件, 可讓 Action Creator 返回函數(普通的 Action Creator 默認返回一個對象)。若是action creator 返回的是一個函數,就執行它,若是不是,就按照原來的next(action)執行。
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import reducer from './reducers'; const store = createStore( reducer, applyMiddleware(thunk) );
redux-thunkexport default
的是createThunkMiddleware()
,這個函數返回的是一個柯里化過的函數。
function createThunkMiddleware(extraArgument) { return function({ dispatch, getState }) { return function(next){ return function(action){ if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } } }
栗子
fetchPosts
返回了一個函數,而普通的 Action Creator 默認返回一個對象。dispatch
和getState
,而普通的 Action Creator 的參數是 Action 的內容。requestPosts(title)
,表示操做開始。const fetchPosts = title => (dispatch, getState) => { dispatch(requestPosts(title)); return fetch(url) .then(response => response.json()) .then(json => dispatch(receivePosts(title, json))); }; }; store.dispatch(fetchPosts('test'));
既然使用redux-thunk中間件可讓 Action Creator 返回函數,固然也能夠返回其餘值。另外一種異步操做的解決方案是讓 Action Creator 返回一個 Promise 對象。這就須要使用redux-promise
中間件。
import { createStore, applyMiddleware } from 'redux'; import promiseMiddleware from 'redux-promise'; import reducer from './reducers'; const store = createStore( reducer, applyMiddleware(promiseMiddleware) );
栗子
const fetchPosts = (dispatch, title) => new Promise((resolve, reject)=> { dispatch(requestPosts(title)); return fetch(url).then(response => { type: 'FETCH_POSTS', payload: response.json() }); });
Redux 讓狀態管理變得很冗長,大量的action、actionCreator、reducer讓開發者不斷在寫重複的代碼。redux-actions就解決了這個問題,讓編寫redux狀態管理變得簡單起來。
主要API有createAction(s)
、handleAction(s)
、combineActions
。
建立一個action: createAction(type)
import { createAction } from 'redux-actions'; export const increment = createAction('INCREMENT'); export const decrement = createAction('DECREMENT'); increment(); // { type: 'INCREMENT' } decrement(); // { type: 'DECREMENT' } increment(10); // { type: 'INCREMENT', payload: 10 } decrement([1, 42]); // { type: 'DECREMENT', payload: [1, 42] }
建立多個action: createActions(actionMap, ...identityActions[, options])
第一個參數 actionMap 是一個對象,以 action type 爲鍵名,鍵值value有三種形式:
action
建立的時候傳入的參數,返回結果會做爲到生成的action
的payload
的value。createActions({ ADD_TODO: todo => ({ todo }), // payload creator REMOVE_TODO: [ todo => ({ todo }), // payload creator (todo, warn) => ({ todo, warn }) // meta ] });
處理action
,返回一個reducer
,處理一種類型的action type
。
處理一個action: handleAction(type, reducer, defaultState)
import { handleAction } from 'redux-actions'; handleAction( 'APP/COUNTER/INCREMENT', (state, action) => ({ counter: state.counter + action.payload.amount }), defaultState );
處理多個action: handleActions(reducerMap, defaultState[, options])
const reducer = handleActions( { INCREMENT: (state, action) => ({ counter: state.counter + action.payload }), DECREMENT: (state, action) => ({ counter: state.counter - action.payload }) }, { counter: 0 } );
React Developer Tools、Redux DevTools 能夠給開發人員在研發階段調試程序帶來極大的方便。 可是上了生產環境後,應該將禁止 DevTools。
Redux DevTools的做者已經給出了標準的解決方案。具體實現步驟以下:
process.env.NODE_ENV = JSON.stringify('production')
redux-devtools-extension/developmentOnly
引入方法import { createStore, applyMiddleware } from 'redux'; import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; const store = createStore( rootReducer, composeWithDevTools(middlewareEnhancer) );