1.安裝
redux是獨(dú)立的數(shù)據(jù)狀態(tài)管理插件,要想和react搭配使用,還需要添加react-redux用來將二者鏈接起來,發(fā)揮其強(qiáng)大作用。
npm install redux react-redux --save
2.創(chuàng)建唯一數(shù)據(jù)中心store
利用redux的createStore創(chuàng)建唯一數(shù)據(jù)中心store,createStore接受reducer為第一個(gè)參數(shù),中間件作為第二個(gè)參數(shù)(此處引用的redux-thunk插件用于擴(kuò)展reducer不僅可以接受action對(duì)象作為參數(shù),同時(shí)還能接受一個(gè)函數(shù)作為參數(shù),由此實(shí)現(xiàn)在action中實(shí)現(xiàn)異步請(qǐng)求)。
subscribe 這個(gè)函數(shù)是用來去訂閱 store 的變化,比如你每次對(duì) store 進(jìn)行 dispatch(action) 都會(huì)觸發(fā) subscribe 注冊(cè)的函數(shù)調(diào)用,這個(gè)在實(shí)際情況不是必須要的,看自己的應(yīng)用場景,比如你想監(jiān)控 store 的全局變化時(shí) 可以用 subscript 訂閱一下,然后作一些反應(yīng)。
import { createStore, applyMiddleware } from 'redux';
import reducers from '../reducers/index'
import thunk from 'redux-thunk'
let store = createStore(reducers, applyMiddleware(thunk));
// 可以手動(dòng)訂閱更新,也可以事件綁定到視圖層。
store.subscribe(() =>
console.log(store.getState())
);
export default store;
3.修改store內(nèi)數(shù)據(jù)的唯一動(dòng)作提交action
要想修改store內(nèi)的數(shù)據(jù)唯一方法就是提交action,action是一個(gè)帶有tyoe屬性的對(duì)象,其他屬性可以任意填寫。編寫action需要注意幾點(diǎn):
- 單獨(dú)存儲(chǔ)action的type,避免不必要的無提示的錯(cuò)誤編寫;
- 通過函數(shù)創(chuàng)建action,前面我們說過,引入了redux-thunk插件,他允許action返回一個(gè)函數(shù)作為dispatch的對(duì)象,例如actionCreator.js中的getData函數(shù)。
//actionTypes.js
const Types = {
SET_DATA: 'SET_DATA',
SET_NORMAL: 'SET_NORMAL',
SET_LOADING: 'SET_LOADING'
};
export default Types;
// actionCreator.js
import Types from './actionTypes';
const actionCreator = {
setLoading: () => {
return {
type: Types.SET_LOADING,
payload : {
loading: true
}
}
},
getData: () => {
return (dispatch, getState) => {
let action = {
type: Types.SET_DATA,
payload: {
loading: false
}
};
console.log(getState());
setTimeout(() => {
dispatch(action);
}, 3000);
}
},
normal: () => {
return {
type: Types.SET_NORMAL,
payload: {
count: 4
}
}
}
}
export default actionCreator;
4.神奇的reducer
reducer是唯一可以更改store中數(shù)據(jù)的方法,而且reducer應(yīng)該是一個(gè)沒有任何副作用的純函數(shù),即固定輸入,固定輸出(每次輸入同樣的數(shù)據(jù)都應(yīng)該得到唯一的輸出),這里的副作用值得是setTimeout、異步請(qǐng)求等操作。以下代碼展示了將reducer如何進(jìn)行拆分,利用redux的combineReducers函數(shù),將多個(gè)reducer合并為一個(gè)reducer返回。導(dǎo)出的大reducer作為createStore的第一參數(shù)。
// index.js
import { combineReducers } from 'redux'
import home from './home'
import detail from './detail'
export default combineReducers({
home,
detail
});
// reducer 是純函數(shù),輸入固定,輸出固定
// 不能含有任何副作用代碼
import Types from '../actions/actionTypes'
let defaultState = {
flag: 1,
loading: false
};
const home = (state = defaultState, action) => {
switch (action.type) {
case Types.SET_DATA:
return Object.assign({}, state, {
flag: state.flag + 1,
loading: action.payload.loading
})
case Types.SET_LOADING:
return Object.assign({}, state, {
loading: action.payload.loading
})
case Types.SET_NORMAL:
return Object.assign({}, state, {
flag: state.flag + action.payload.count
})
default:
return state;
}
}
export default home;
//detail.js
let defaultState = {};
const detail = (state = defaultState, action) => {
switch(action.type){
default:
return state;
}
}
export default detail;
5.react和redux的強(qiáng)力膠水react-redux
react作為視圖層框架,用于管理用戶界面,而redux作為數(shù)據(jù)層框架,用于幾種管理數(shù)據(jù),如何將二者聯(lián)系起來,統(tǒng)一管理數(shù)據(jù),數(shù)據(jù)變動(dòng)觸發(fā)視圖更新呢?答案就是強(qiáng)力膠水react-redux,react-redux利用connect函數(shù)將react視圖組件和store中的數(shù)據(jù)連接起來,具體代碼:
import React, { Component } from 'react';
import { Button } from 'antd';
import { connect } from 'react-redux';
import actionCreator from '../actions/actionCreator';
class TestRedux extends Component {
handleClick () {
this.props.setLoading();
this.props.getData();
}
render () {
return (
<div>
<div>{this.props.flag}</div>
<Button
onClick={this.handleClick.bind(this)}
type="primary"
>增加</Button>
<Button
onClick={this.props.getCount}
type="primary"
>增加4</Button>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
console.log(ownProps);
return {
flag: state.home.flag
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
console.log(ownProps);
return {
getData () {
const action = actionCreator.getData();
dispatch(action);
},
getCount () {
const action = actionCreator.normal();
dispatch(action);
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(TestRedux);
react-redux的 connect函數(shù)接受兩個(gè)參數(shù)mapStateToProps和mapDispatchToProps,正如兩個(gè)函數(shù)的名字一樣,兩個(gè)函數(shù)返回一個(gè)映射,一個(gè)是state => props的映射,一個(gè)是dispatch => props 的映射,將store中的數(shù)據(jù)映射到對(duì)應(yīng)組件的props屬性上,這樣我們便可以再組件中使用這些屬性。
注意
利用redux-thunk我們返回了getData這個(gè)異步函數(shù)action,細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn),我再組件中映射dispatch時(shí),利用actionCreator創(chuàng)建了getData的action,然后立即dispatch了這個(gè)action,而且在dispatch的這個(gè)函數(shù)中進(jìn)行了異步操作,當(dāng)操作成功后再次調(diào)用dispath,整個(gè)數(shù)據(jù)更新操作中dispath了兩次,我的理解是
1、立即發(fā)出的dispatch用于告知redux,我要更新數(shù)據(jù),但是我現(xiàn)在不更新,你等我下一次通知。
2、異步請(qǐng)求成功后發(fā)出的dispatch就是這個(gè)下一次通知,然后redux相應(yīng)這個(gè)更新,修改store中的數(shù)據(jù)。
結(jié)語
react和redux分管視圖和數(shù)據(jù),實(shí)現(xiàn)了數(shù)據(jù)視圖的真正分離,這是在大型應(yīng)用中很好地,也是易于維護(hù)的,但是任何事情都有利有弊,當(dāng)應(yīng)用逐漸變大,action和reducer的量也會(huì)相應(yīng)變得更加繁瑣,雖然數(shù)據(jù)變化和流轉(zhuǎn)是明確的但是對(duì)于多數(shù)項(xiàng)目來說,還達(dá)不到足夠大,敏捷、高效有時(shí)才是王道,這就是我理解的近年來vue盛行的原因。vue憑借其易學(xué)、易用性迅速崛起。為了解決redux的繁瑣,mobx應(yīng)運(yùn)而生,mobx采用類似vue的響應(yīng)機(jī)制,細(xì)粒度的觀測讓數(shù)據(jù)變化不再這么繁瑣,下節(jié),我們會(huì)剖析mobx的基礎(chǔ)使用,一起學(xué)起來吧!