Appearance
combineReducers
本节目标:理解“combineReducers”的核心思路,并能把它用于实际开发或面试表达。 在项目中,我们一般定义多个
recducer; 主要是为了进行分类组织; 不同的reducer对一个页面中的state进行处理; 而这个页面state只是全局唯一store树的一个分支而已; 对于这多个reducer,我们是想把它们管理的子store存储在同一个store对象中,因此需要合并reducer; 这样的结果是,每一个被合并的reducer,都会在store中建立一个键值对,存储各自的状态值;
src\redux\combineReducers.js -combineReducers
functioncombineReducers(reducers){/*** state 老的总状态 * action 动作 */return function
(state= {},
action){let nextState = {};//reducers = {counter1,counter2}for
(letkey in
reducers){//nextState.counter1 = counter1(oldCounter1State,action);
nextState[key]=
reducers[key](state[key],action); `}`
`return`
nextState;}
}
exportdefault
combineReducers;src\index.js
importReact from
'react';
importReactDOM from
'react-dom';
importCounter1 from
'./components/Counter1';
importCounter2 from
'./components/Counter2';
ReactDOM.render(\<\>
<Counter1/>
<Counter2/\>
</>,document.getElementById('root')
);src\store\action-types.js
//Counter1派发的动作的action
type
exportconst ADD1 =
'ADD1';
exportconst MINUS1 =
'MINUS1';
//Counter2派发的动作的action
type
exportconst ADD2 =
'ADD2';
exportconst MINUS2 =
'MINUS2';
exportconst CHANGE_COLOR =
'CHANGE_COLOR';开始分类组织reduce,它需要
actionTypesintialStatereducer
src\store\reducers\counter1.js
import* as actionTypes from
'../action-types'
//Counter1组件对应的
state
letintialState = { number:
0,color: 'black'
};
//Counter1组件对应的
reducer
functioncounter1(state=
intialState,action){switch
(action.type){case
actionTypes.ADD1: `return` `{`
...state,number:
state.number+ 1 };case
actionTypes.MINUS1: `return` `{`
...state,number:
state.number- 1 };case
actionTypes.CHANGE_COLOR: `return` `{`
...state,color:
action.payload};
default: `return`
state;}
}
exportdefault counter1
src\store\reducers\counter2.js
import* as actionTypes from
'../action-types'
//Counter1组件对应的
state
letintialState = { number:
0,color: 'black'
};
//Counter1组件对应的
reducer
functioncounter2(state=
intialState,action){switch
(action.type){case
actionTypes.ADD2: `return` `{`
...state,number:
state.number+ 1 };case
actionTypes.MINUS2: `return` `{`
...state,number:
state.number- 1 };case
actionTypes.CHANGE_COLOR: `return` `{`
...state,color:
action.payload};
default: `return`
state;}
}
exportdefault counter2
src\store\reducers\index.js
import{ combineReducers } from
'redux';
importcounter1 from
'./counter1';
importcounter2 from
'./counter2';
letrootReducer =
combineReducers({counter1,counter2
});
exportdefault
rootReducer;
/*** reducer rootReducer:* state {counter1:{number:0},counter:{number:0}}*/
/*** 项目 不管规模多大 * 只有一个store* store只有一个state* store只能有一个reducer* 写多个reducer,然后经过一个方法合并成一个reducer就可以了 */
src\store\index.js
import{ createStore } from
'redux';
importrootReducer from
'./reducers';
letstore =
createStore(rootReducer);
exportdefault
store;src\store\actions\counter1.js
import* as actionTypes from
'../action-types';
letactions = {
add1(){return { type:
actionTypes.ADD1};},
minus1(){return { type:
actionTypes.MINUS1};},
changeColor(color){return { type:
actionTypes.CHANGE_COLOR,payload: color };
}
}
exportdefault
actions;src\store\actions\counter2.js
import* as actionTypes from
'../action-types';
letactions = {
add2(){return { type:
actionTypes.ADD2};},
minus2(){return { type:
actionTypes.MINUS2};
}
}
exportdefault
actions;src\components\Counter1.js
importReact,{ Component } from
'react'
import{ bindActionCreators } from
'redux';
importstore from
'../store';
importactions from
'../store/actions/counter1';
letboundActions =
bindActionCreators(actions,store.dispatch);
classCounter1 extends Component {state =
store.getState().counter1componentDidMount(){
this.unsubscribe=
store.subscribe(()=\> {
this.setState(store.getState().counter1); `});`
}
componentWillUnmount(){
this.unsubscribe();}
render(){return (
<divstyle={{color:
this.state.color}}><p>{this.state.number}</p><buttononClick={boundActions.add1}>+</button><buttononClick={boundActions.minus1}>-</button><buttononClick={()=\>
boundActions.changeColor('red')}>改成红色
</button></div> `)`
}
}
exportdefault
Counter1;
/*** 组件关联仓库两个方向 * 输入 组件里使用仓库提供的状态进行组件的渲染 * 输出 在组件可以派发动作从而修改仓库中的状态 */
src\components\Counter2.js
importReact,{ Component } from
'react'
import{ bindActionCreators } from
'redux';
importstore from
'../store';
importactions from
'../store/actions/counter2';
letboundActions =
bindActionCreators(actions,store.dispatch);
classCounter2 extends Component {state =
store.getState().counter2componentDidMount(){
this.unsubscribe=
store.subscribe(()=\> {
this.setState(store.getState().counter2); `});`
}
componentWillUnmount(){
this.unsubscribe();}
render(){return (
<divstyle={{color:
this.state.color}}><p>{this.state.number}</p><buttononClick={boundActions.add2}>+</button><buttononClick={boundActions.minus2}>-</button></div> `)`
}
}
exportdefault
Counter2;src\redux\createStore.js
/*** 创建仓库 * @param {*} reducer 处理器 * @param {*} preloadedState 默认状态 或者 说初始状态
*/
functioncreateStore(reducer,preloadedState){let state =
preloadedState;let listeners = [];function
getState(){return
state;}function
dispatch(action){//根据老状态和action动作,计算新状态 state =
reducer(state,action);listeners.forEach(l=\>
l());}function
subscribe(listener){
listeners.push(listener);}
dispatch({type: '@@REDXU/INIT' });return {
getState,//用来获取当前的仓库中的状态
dispatch,//向仓库派发动作
subscribe,//用来订阅仓库中的状态的变化
}
}
exportdefault
createStore;src\redux\bindActionCreator.js
/**** @param {*} actionCreator function add(){return {type:ADD};}* @param {*} dispatch store.dispatch
*/
functionbindActionCreator(actionCreator,dispatch){return function
(...args){return
dispatch(actionCreator.apply(this,args));}
}
/**** @param {*} actionCreators action的创建者 此处可以只传一个创建者,也就是一个函数,也可以传一个对象 * @param {*} dispatch
*/
functionbindActionCreators(actionCreators,dispatch){if
(typeofactionCreators ===
'function'){return
bindActionCreator(actionCreators,dispatch)}const boundActionCreators = {};for
(constkey in
actionCreators){const actionCreator =
actionCreators[key];boundActionCreators[key]=
bindActionCreator(actionCreator,dispatch)}return
boundActionCreators;
}
exportdefault
bindActionCreators;src\redux\index.js
export{ default as createStore } from
'./createStore';
export{ default as bindActionCreators } from
'./bindActionCreators';