在redux——入門1里面,我簡要介紹了redux的核心概念,并舉了一個簡單的計數(shù)器demo的例子,用于展示在react中怎么使用redux?,F(xiàn)在,我打算把這個簡單的demo變得復(fù)雜一點(diǎn),引入react-redux和redux中一些其他的概念。
工具分享
在本篇正式開始之前,我想先分享一個用于快速構(gòu)建react應(yīng)用的腳手架工具,傳送門:https://github.com/facebookincubator/create-react-app
概念引入
我會在這個升級版的demo里面,引入三個東西,Provider(react-redux),combineReducers(redux),connect(react-redux),如果你想更深入的了解react-redux中的各個角色,這里有個很好的解釋https://github.com/jasonslyvia/a-cartoon-intro-to-redux-cn
Provider
這是一個組件,沒有其他特殊的作用,但是我們需要將它包裹在整個組件樹的最外層,只有這樣,其內(nèi)部的子孫組件才能使用connect來綁定store。
connect
這是一個函數(shù),由react-redux提供,其返回依然是一個函數(shù),該函數(shù)會處理視圖與store綁定的細(xì)節(jié),具體的使用方法后面會做介紹。
combineReducers
這也是一個函數(shù)。在上一章,我們的reducer是一個單一的函數(shù),在處理類似于計數(shù)器這樣的簡單應(yīng)用時,我們不會看出有什么問題,但是當(dāng)整個系統(tǒng)變得復(fù)雜后,單一的reducer就會變得臃腫不堪,所以我們需要對reducer進(jìn)行分片,每一個reducer用于單獨(dú)處理一部分state,而combineReducers就是將分片的reducer合并為一個整體,這個函數(shù)的實現(xiàn)也比較簡單。
counter升級版
因為參照了react的官方示例,因此整個例子所使用的語法和上個簡化版的例子會有比較大的出入。
入口文件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')
);
同簡化版本相比,這里我們引入了Provider,并將其包裹在了組件的最外層。
reducers/index.js
import {combineReducers} from 'redux';
import counter from './counter';
const all = combineReducers({
count: counter
});
export default all;
在這里,我們調(diào)用了combineReducers方法,將counter這個reducer合并到主reducer上,因為計數(shù)器這個demo很簡單,所以我們只將state劃分了一個屬性count,而counter這個reducer和簡化版的沒有什么區(qū)別,姑且還是貼一下代碼
export default (state=0, action) => {
switch(action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
前面說過,combineReducer的實現(xiàn)其實是蠻簡單的,其實就是返回一個函數(shù),每次處理action的時候,這個函數(shù)會遍歷所有的reducer來處理這個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>
);
};
這個沒什么可以講的,主要看接下來的InputBox和ShowBox
containers/input-box
這是一個純輸入組件
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)然,如果之前完全沒接觸過connect函數(shù),看這段代碼可能會有點(diǎn)頭疼,可以先移步這里connect的api文檔。我也可以簡單介紹下connect的使用方法,它支持四個參數(shù),我這里只介紹前兩個,后兩個因為我并沒怎么用過,所以暫時不講。
第一個參數(shù)是mapStateToProps(state, [ownProps]),用于選擇性的將state中的屬性注入到組件的props中,我在show-box中使用了這個參數(shù),所以請看后面的代碼。
第二個參數(shù)是mapDispatchToProps(dispatch, [ownProps]),用于將需要觸發(fā)dispatch的方法,注入到組建的props中,在上面的input-box中,我使用了這個參數(shù),將onIncrement和onDecrement兩個用于dispatch的方法注入到了InputBox中。
container/show-box
這是一個純展示的組件
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é)
雖然是說是升級版,但也只是多引入了幾個東西,總體來說還是算簡單,只是概念多了,容易讓人糊涂,我被繞了一個上午,好在現(xiàn)在總算有點(diǎn)清醒了,所以記下這些東西,方便之后的回顧。