在redux——入門1里面,我簡(jiǎn)要介紹了redux的核心概念,并舉了一個(gè)簡(jiǎn)單的計(jì)數(shù)器demo的例子盛垦,用于展示在react中怎么使用redux。現(xiàn)在瓤漏,我打算把這個(gè)簡(jiǎn)單的demo變得復(fù)雜一點(diǎn)腾夯,引入react-redux和redux中一些其他的概念。
工具分享
在本篇正式開(kāi)始之前赌蔑,我想先分享一個(gè)用于快速構(gòu)建react應(yīng)用的腳手架工具俯在,傳送門:https://github.com/facebookincubator/create-react-app
概念引入
我會(huì)在這個(gè)升級(jí)版的demo里面,引入三個(gè)東西娃惯,Provider(react-redux)跷乐,combineReducers(redux),connect(react-redux)趾浅,如果你想更深入的了解react-redux中的各個(gè)角色愕提,這里有個(gè)很好的解釋https://github.com/jasonslyvia/a-cartoon-intro-to-redux-cn
Provider
這是一個(gè)組件,沒(méi)有其他特殊的作用皿哨,但是我們需要將它包裹在整個(gè)組件樹(shù)的最外層浅侨,只有這樣,其內(nèi)部的子孫組件才能使用connect來(lái)綁定store证膨。
connect
這是一個(gè)函數(shù)如输,由react-redux提供,其返回依然是一個(gè)函數(shù)央勒,該函數(shù)會(huì)處理視圖與store綁定的細(xì)節(jié)不见,具體的使用方法后面會(huì)做介紹。
combineReducers
這也是一個(gè)函數(shù)崔步。在上一章稳吮,我們的reducer是一個(gè)單一的函數(shù),在處理類似于計(jì)數(shù)器這樣的簡(jiǎn)單應(yīng)用時(shí)井濒,我們不會(huì)看出有什么問(wèn)題灶似,但是當(dāng)整個(gè)系統(tǒng)變得復(fù)雜后列林,單一的reducer就會(huì)變得臃腫不堪,所以我們需要對(duì)reducer進(jìn)行分片酪惭,每一個(gè)reducer用于單獨(dú)處理一部分state希痴,而combineReducers就是將分片的reducer合并為一個(gè)整體,這個(gè)函數(shù)的實(shí)現(xiàn)也比較簡(jiǎn)單撞蚕。
counter升級(jí)版
因?yàn)閰⒄樟藃eact的官方示例润梯,因此整個(gè)例子所使用的語(yǔ)法和上個(gè)簡(jiǎn)化版的例子會(huì)有比較大的出入过牙。
入口文件index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import reducer from './reducers';
import Root from './components/root';
let store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<Root></Root>
</Provider>,
document.getElementById('root')
);
同簡(jiǎn)化版本相比甥厦,這里我們引入了Provider,并將其包裹在了組件的最外層寇钉。
reducers/index.js
import {combineReducers} from 'redux';
import counter from './counter';
const all = combineReducers({
count: counter
});
export default all;
在這里刀疙,我們調(diào)用了combineReducers方法,將counter這個(gè)reducer合并到主reducer上扫倡,因?yàn)橛?jì)數(shù)器這個(gè)demo很簡(jiǎn)單谦秧,所以我們只將state劃分了一個(gè)屬性count,而counter這個(gè)reducer和簡(jiǎn)化版的沒(méi)有什么區(qū)別撵溃,姑且還是貼一下代碼
export default (state=0, action) => {
switch(action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
前面說(shuō)過(guò)疚鲤,combineReducer的實(shí)現(xiàn)其實(shí)是蠻簡(jiǎn)單的,其實(shí)就是返回一個(gè)函數(shù)缘挑,每次處理action的時(shí)候集歇,這個(gè)函數(shù)會(huì)遍歷所有的reducer來(lái)處理這個(gè)action,然后將所有結(jié)果打包返回语淘,代碼和下面類似
// combineReducers
const combineReducers = ( reducers ) => {
return ( state = {}, action ) => {
return Object.keys(reducers).reduce(
( nextState, key ) => {
nextState[key] = reducers[key](
state[key],
action
);
return nextState;
},
{}
);
};
};
components/root.js
這是我們的根組件
import React from 'react';
import InputBox from '../containers/input-box';
import ShowBox from '../containers/show-box';
export default () => {
return (
<div>
<InputBox></InputBox>
<ShowBox></ShowBox>
</div>
);
};
這個(gè)沒(méi)什么可以講的诲宇,主要看接下來(lái)的InputBox和ShowBox
containers/input-box
這是一個(gè)純輸入組件
import React from 'react';
import {connect} from 'react-redux';
let InputBox = ({onIncrement, onDecrement}) => {
return (
<div>
<button type="button" onClick={onIncrement}>+++</button>
<button type="button" onClick={onDecrement}>---</button>
</div>
);
};
let mapDispatchToProps = (dispatch) => ({
onIncrement: () => dispatch({type: 'INCREMENT'}),
onDecrement: () => dispatch({type: 'DECREMENT'})
});
InputBox = connect(undefined, mapDispatchToProps)(InputBox);
export default InputBox;
在這里我們調(diào)用了react-redux的connect方法,當(dāng)然惶翻,如果之前完全沒(méi)接觸過(guò)connect函數(shù)姑蓝,看這段代碼可能會(huì)有點(diǎn)頭疼,可以先移步這里connect的api文檔吕粗。我也可以簡(jiǎn)單介紹下connect的使用方法纺荧,它支持四個(gè)參數(shù),我這里只介紹前兩個(gè)颅筋,后兩個(gè)因?yàn)槲也](méi)怎么用過(guò)宙暇,所以暫時(shí)不講。
第一個(gè)參數(shù)是mapStateToProps(state, [ownProps])
垃沦,用于選擇性的將state中的屬性注入到組件的props中客给,我在show-box中使用了這個(gè)參數(shù),所以請(qǐng)看后面的代碼肢簿。
第二個(gè)參數(shù)是mapDispatchToProps(dispatch, [ownProps])
靶剑,用于將需要觸發(fā)dispatch的方法蜻拨,注入到組建的props中,在上面的input-box中桩引,我使用了這個(gè)參數(shù)缎讼,將onIncrement
和onDecrement
兩個(gè)用于dispatch的方法注入到了InputBox中。
container/show-box
這是一個(gè)純展示的組件
import React from 'react';
import {connect} from 'react-redux';
let ShowBox = ({count}) => {
return (
<div>
<p>{count}</p>
</div>
);
};
let mapStateToProps = (state) => ({
count: state.count
});
ShowBox = connect(mapStateToProps)(ShowBox);
export default ShowBox;
唯一需要注意的是用了mapStateToProps
總結(jié)
雖然是說(shuō)是升級(jí)版坑匠,但也只是多引入了幾個(gè)東西血崭,總體來(lái)說(shuō)還是算簡(jiǎn)單,只是概念多了厘灼,容易讓人糊涂夹纫,我被繞了一個(gè)上午,好在現(xiàn)在總算有點(diǎn)清醒了设凹,所以記下這些東西舰讹,方便之后的回顧。