1 import { applyMiddleware, createStore } from 'redux'; 2 import thunk from 'redux-thunk'; 3 const store = createStore( 4 reducers, 5 applyMiddleware(thunk) 6 );
1 function createThunkMiddleware(extraArgument) { 2 return ({ dispatch, getState }) => next => action => { 3 if (typeof action === 'function') { 4 return action(dispatch, getState, extraArgument); 5 } 6 return next(action); 7 }; 8 } 9 const thunk = createThunkMiddleware(); 10 thunk.withExtraArgument = createThunkMiddleware; 11 export default thunk;
redux-thunk中間件export default的就是createThunkMiddleware()過的thunk,再看createThunkMiddleware這個函數,返回的是一個柯里化過的函數。咱們再翻譯成ES5的代碼容易看一點html
1 function createThunkMiddleware(extraArgument) { 2 return function({ dispatch, getState }) { 3 return function(next){ 4 return function(action){ 5 if (typeof action === 'function') { 6 return action(dispatch, getState, extraArgument); 7 } 8 return next(action); 9 }; 10 } 11 } 12 }
能夠看出來redux-thunk最重要的思想,就是能夠接受一個返回函數的action creator。若是這個action creator 返回的是一個函數,就執行它,若是不是,就按照原來的next(action)執行。 正由於這個action creator能夠返回一個函數,那麼就能夠在這個函數中執行一些異步的操做。例如:node
1 export function addCount() { 2 return {type: ADD_COUNT} 3 } 4 export function addCountAsync() { 5 return dispatch => { 6 setTimeout( () => { 7 dispatch(addCount()) 8 },2000) 9 } 10 }
1 import { createStore, applyMiddleware } from 'redux'; 2 import thunkMiddleware from 'redux-thunk'; 3 import combineReducers from '../reducers/reducers'; 4 import promiseMiddleware from 'redux-promise' 5 import { createLogger } from 'redux-logger'; 6 import createHistory from 'history/createBrowserHistory'; 7 const history = createHistory(); 8 const arr = [thunkMiddleware,promiseMiddleware]; 9 if (process.env.NODE_ENV !== 'pro') arr.push(createLogger({ 10 diff: true, 11 collapsed: true, 12 })); 13 let store = createStore(combineReducers, applyMiddleware(...arr)); 14 export default store;
action.jsreact
1 import types from '../store/types'; 2 import { 3 get_user_info //題主是本地配的mock服務,也能夠用一個定時器返回數據實現異步 4 } from '../api/userInfo' 5 export const getUserInfo = () => (dispatch) => 6 dispatch({ 7 type: types.GET_USER_INFO_REQUEST, 8 payload: Promise.resolve(get_user_info()) 9 })
reducer.jsnpm
1 import types from '../store/types'; 2 import { reducerCreators } from '../util/index'; 3 const initState = { 4 isLoading: false, 5 userInfo: {}, 6 errorMsg: '' 7 }; 8 9 export default reducerCreators(initState, { 10 [`${types.GET_USER_INFO_REQUEST}`]: (state, data) => { 11 return Object.assign({}, state, { 12 userInfo: data.data 13 }) 14 } 15 })
reducerCreators (../util/index) 從新生成reducer使其符合範式redux
1 export function reducerCreators (initialState, actionTypeMapList) { 2 return (state = initialState, action) => { 3 const reducerInstance = typeof actionTypeMapList === 'object' && 4 actionTypeMapList[action.type] ? 5 actionTypeMapList[action.type](state, action.payload ? 6 action.payload : {}, action.params) : 7 state; 8 return reducerInstance; 9 }; 10 }
view.jsapi
1 import React, { Component } from 'react'; 2 import { connect } from 'react-redux'; 3 import { bindActionCreators } from 'redux' 4 import { getUserInfo } from 'actions/userInfo'; 5 class UserInfo extends Component { 6 render() { 7 const { userInfo, isLoading, errMsg } = this.props.userInfo; 8 return (<div> 9 { 10 isLoading ? '請求中' : 11 (errMsg ? errMsg : 12 <div> 13 <p>用戶信息:</p> 14 <p>用戶名:{userInfo.name}</p> 15 <p>介紹:{userInfo.intro}</p> 16 </div> 17 ) 18 } 19 <button onClick={() => this.props.getUserInfo()}>請求用戶信息</button> 20 </div>) 21 } 22 } 23 24 const mapStateToProps = (state) => { 25 return { 26 userInfo: state.userInfo, 27 } 28 } 29 30 const mapDispatchToProps = (dispatch) => { 31 return { 32 getUserInfo: bindActionCreators(getUserInfo, dispatch) 33 } 34 } 35 36 export default connect(mapStateToProps, mapDispatchToProps)(UserInfo);
3、Redux-saga數組
1 import { createStore, applyMiddleware } from 'redux'; 2 import combineReducers from '../reducers/reducers'; 3 import promiseMiddleware from 'redux-promise' 4 import createSagaMiddleware from 'redux-saga' 5 import mySaga from './saga' 6 import { createLogger } from 'redux-logger'; 7 const sagaMiddleware = createSagaMiddleware(mySaga) 8 const arr = [sagaMiddleware]; 9 arr.push(promiseMiddleware) 10 if (process.env.NODE_ENV !== 'pro') arr.push(createLogger({ 11 diff: true, 12 collapsed: true, 13 })); 14 export const store = createStore(combineReducers, applyMiddleware(...arr)); 15 sagaMiddleware.run(mySaga)
這裏saga也用npm安裝一下,而後像和thunk同樣的引入到store中,不一樣的是須要用createSagaMiddleware工廠函數建立一個Saga middleware,而後鏈接到store上,以後便使用sagaMiddleware.run(mySaga) 運行Saga。promise
1 import { call, put, takeEvery, takeLatest, take } from 'redux-saga/effects' 2 import types from '../store/types' 3 function* fetchUser(action) { 4 try { 5 const data = yield action.payload 6 yield put({ type: `${action.type}_SUCCESS`, payload: data }) 7 } catch (e) { 8 yield put({ type: `${action.type}_FAILD`, message: e.message }) 9 } 10 } 11 function* mySaga() { 12 yield takeLatest(types['GET_USER_INFO'], fetchUser) 13 } 14 export default mySaga
1 import types from '../store/types'; 2 import { 3 get_user_info 4 } from '../api/userInfo' 5 export const getUserInfo = (params) => 6 ({ 7 type: types.GET_USER_INFO, 8 payload: get_user_info() 9 })
向saga提供action的type和異步請求的結果瀏覽器
reducer.js緩存
1 import types from '../store/types'; 2 import { reducerCreators } from '../util/index'; 3 const initState = { 4 isLoading: false, 5 userInfo: {}, 6 errorMsg: '' 7 }; 8 export default reducerCreators(initState, { 9 [`${types.GET_USER_INFO}_SUCCESS`]: (state, data) => { 10 return Object.assign({}, state, { 11 userInfo: data.data 12 }) 13 } 14 })
view.js
1 import React, { Component } from 'react'; 2 import { connect } from 'react-redux'; 3 import { bindActionCreators } from 'redux' 4 import { getUserInfo } from 'actions/userInfo'; 5 6 class UserInfo extends Component { 7 render() { 8 const { userInfo, isLoading, errMsg } = this.props.userInfo; 9 10 return (<div> 11 { 12 isLoading ? '請求中' : 13 (errMsg ? errMsg : 14 <div> 15 <p>用戶信息:</p> 16 <p>用戶名:{userInfo.name}</p> 17 <p>介紹:{userInfo.intro}</p> 18 </div> 19 ) 20 } 21 <button onClick={() => this.props.getUserInfo()}>請求用戶信息</button> 22 </div>) 23 } 24 } 25 26 const mapStateToProps = (state) => { 27 return { 28 userInfo: state.userInfo, 29 } 30 } 31 32 const mapDispatchToProps = (dispatch) => { 33 return { 34 getUserInfo: bindActionCreators(getUserInfo, dispatch) 35 } 36 } 37 38 export default connect(mapStateToProps, mapDispatchToProps)(UserInfo);
4、redux-thunk與redux-saga優缺點