介紹一下我在之前項目中是如何使用redux的惦银。
redux學(xué)習(xí):http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html
阮一峰老師已經(jīng)在這幾篇文章里講解的很清楚了,我就不班門弄斧了,這里只是說明一下在項目中的使用跪帝。
首先粱哼,安裝
redux:Redux
react-redux:Redux的作者封裝的React專用庫
redux-logger:日志中間件,用于調(diào)試
redux-persist:緩存
redux-thunk:支持異步dispatch
安裝方法谷徙,在package.json文件中的dependencies中添加以下各項
"react-redux": "^5.0.1",
"redux": "^3.6.0",
"redux-logger": "^2.7.4",
"redux-persist": "^4.0.1",
"redux-thunk": "^2.1.0"
然后拒啰,執(zhí)行npm install即可
也可以分開安裝,例如完慧,安裝redux
npm install --save redux (--save代表修改package.json中的dependencies谋旦,關(guān)于npm的使用可以自行百度,給一個菜鳥教程的鏈接:http://www.runoob.com/nodejs/nodejs-npm.html)
準(zhǔn)備工作完畢后,首先從store開始册着,新建一個文件拴孤,添加以下代碼:
import {applyMiddleware, createStore} from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import {persistStore, autoRehydrate} from 'redux-persist';
import {AsyncStorage} from 'react-native';
import reducers from '../reducers/index'; //后面解釋這個
const logger = createLogger();
let middlewares = [
thunk,
logger
];
//解釋一下這個寫法的意思,可以查看源碼甲捏,看到applyMiddleware函數(shù)演熟,可以傳遞參數(shù)‘{...Function} middlewares The middleware chain to be applied’,然后返回一個以createStore函數(shù)為參數(shù)的函數(shù)司顿,最后會返回一個和createStore函數(shù)參數(shù)相同的函數(shù)芒粹,即createAppStore實際是一個function (reducer, preloadedState, enhancer),且這個函數(shù)中持有傳入的createStore函數(shù)大溜,說了一堆函數(shù)可能有點亂化漆,其實就是幾個閉包
let createAppStore = applyMiddleware(...middlewares)(createStore);
export default function configureStore(onComplete: ()=>void){
//同樣的查看autoRehydrate,會看到這個函數(shù)結(jié)構(gòu)基本和applyMiddleware一樣钦奋,所以生成store的過程有很多種寫法获三,其實最后得到的結(jié)果是一樣
const store = autoRehydrate()(createAppStore)(reducers);
let opt = {
storage: AsyncStorage,
transform: [],
whitelist: [],
blacklist: []
};
persistStore(store, opt, onComplete);
return store;
}
下面實現(xiàn)創(chuàng)建store時用到的reducers,隨著項目的增大锨苏,reducer會有很多疙教,所以可以將其進(jìn)行劃分,最后合并到一起伞租。例如這里新建一個price.js的reducer文件贞谓,在文件中如此實現(xiàn):
//數(shù)據(jù)結(jié)構(gòu)因業(yè)務(wù)所定
const initialState = {
datas: null,
status: null,
netMsg: null,
price: null
};
import {Net, Process, Response} from '../net/net';
import Type from '../actions/type';
export default function priceReducer(state=initialState, action){
switch(action.type){
case Type.GETPRICEBASEDATA:
{
switch (action.name) {
case Process.FETCH_BEGIN:
return {
...state,
status: Process.FETCH_BEGIN,
price: null
};
case Process.FETCH_SUCCESS:
return {
...state,
datas: action.payload,
status: Process.FETCH_SUCCESS,
netMsg: action.msg
};
case Process.FETCH_FAIL:
return {
...state,
status: Process.FETCH_FAIL,
netMsg: action.msg
};
default:
return state;
}
}
case Type.CALCULATEPRICE:
{
switch (action.name) {
case Process.FETCH_BEGIN:
return {
...state,
status: Process.FETCH_BEGIN
};
case Process.FETCH_SUCCESS:
return {
...state,
price: action.payload,
status: Process.FETCH_SUCCESS,
netMsg: action.msg
};
case Process.FETCH_FAIL:
return {
...state,
status: Process.FETCH_FAIL,
netMsg: action.msg
};
default:
return state;
}
}
default:
return state;
}
}
同理新建其它reducer,然后在reducers.js文件中合并
import { combineReducers } from 'redux';
import serviceReducer from './service';
import priceReducer from './price';
import answersReducer from './answers';
export default combineReducers({
serviceStore: serviceReducer,
priceStore: priceReducer,
answersStore: answersReducer
});
然后實現(xiàn)action葵诈,同樣action也應(yīng)該劃分實現(xiàn)裸弦,例如price.js的action如下:
import {Net, Process, Api, Response} from '../net/net';
import Type from './type';
const changePriceParams = (name, params) => (dispatch, getState) => {
return dispatch({type: Type.CHANGEPRICEPARAMS, name, params});
};
const calculatePrice = (params) => (dispatch, getState) => {
dispatch({type: Type.CALCULATEPRICE, name: Process.FETCH_BEGIN});
return Net.commonPostModel(Api.CALCULATEPRICEAPI, params, (res)=>{
if (res.code == 0 || res.code == 999) {
dispatch({type: Type.CALCULATEPRICE, name: Process.FETCH_SUCCESS, payload: res.data, msg: res.msg})//res.data
} else {
dispatch({type: Type.CALCULATEPRICE, name: Process.FETCH_FAIL, payload: null, msg: res.msg})
}
})
};
const getPriceBaseData = () => (dispatch, getState) => {
dispatch({type: Type.GETPRICEBASEDATA, name: Process.FETCH_BEGIN});
return Net.commonGetModel(Api.GETPRICEBASEDATAAPI, null, (res)=>{
if (res.code == 0 || res.code == 999) {
dispatch({type: Type.GETPRICEBASEDATA, name: Process.FETCH_SUCCESS, payload: res.data, msg: res.msg})//res.data
} else {
dispatch({type: Type.GETPRICEBASEDATA, name: Process.FETCH_FAIL, payload: null, msg: res.msg})
}
})
};
export {changePriceParams, calculatePrice, getPriceBaseData};
type.js表示action的標(biāo)示
const Type = {
get GETSERVICEMAIN() {return 'GETSERVICEMAIN'},
get CHANGEPRICEPARAMS() {return 'CHANGEPRICEPARAMS'},
get GETPRICERULE() {return 'GETPRICERULE'},
get SWITCHSECTION() {return 'SWITCHSECTION'},
get GETPRICEBASEDATA() {return 'GETPRICEBASEDATA'},
get CALCULATEPRICE() {return 'CALCULATEPRICE'}
};
export default Type;
各部分定義完畢后,在根文件如下實現(xiàn):
import React, { Component } from 'react';
import { Provider } from 'react-redux'; //Provider利用了context機(jī)制將store對象傳遞到各個子控件
import configureStore from './store/index';
let store = configureStore();
import Root from './root';
export default class App extends Component{
render(){
return (
<Provider store={store}>
<Root />
</Provider>
)
}
}
在每個子控件中export時作喘,如下寫:
import { connect } from 'react-redux';
export default connect()(Root);
另外兩個參數(shù)可選實現(xiàn)
import {changePriceParams, calculatePrice, getPriceBaseData} from '../actions/price';
//映射state到props理疙,即獲取時直接寫this.props.price即可,不再使用this.state(不是不能用this.state泞坦,只是和react-redux的設(shè)計有悖)
const mapStateToProps = (state) => {
return {
params: state.priceStore.params,
datas: state.priceStore.datas,
status: state.priceStore.status,
netMsg: state.priceStore.netMsg,
price: state.priceStore.price
}
};
//映射dispatch到props窖贤,即使用時this.props.calculatePrice(...)即可
const mapDispatchToProps = (dispatch) => {
return {
changePriceParams: (name, text)=> {
dispatch(changePriceParams(name, text))
},
getPriceBaseData: ()=> {
dispatch(getPriceBaseData())
},
calculatePrice: (params)=> {
dispatch(calculatePrice(params))
}
}
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Price);
最后,在控件中即可如下使用:
render() {
if (this.props.status === Process.FETCH_BEGIN) {
showLoading(null);
this.loading = true;
} else if (this.props.status === Process.FETCH_FAIL && this.loading) {
showError(this.props.netMsg);
this.loading = false;
} else {
hideHUD();
}
return this._mainView();
}
在需要計算價格的地方贰锁,執(zhí)行this.props.calculatePrice(params);即可赃梧。
調(diào)用相應(yīng)action,然后傳遞至reducer修改store豌熄,然后更新界面授嘀,這些都會自動執(zhí)行
這樣UI可以專心UI,業(yè)務(wù)可以專心業(yè)務(wù)锣险,數(shù)據(jù)存儲專心存儲蹄皱,網(wǎng)絡(luò)請求專心網(wǎng)絡(luò)览闰,完美分割。