redux导出一个对象,对象拥有createStore,bindActionCreators,combineReducers,applyMiddleware这几个核心的key。
import createStore from './createStore.js';
import bindActionCreators from './bindActionCreators.js';
import combineReducers from './combineReducers.js';
import applyMiddleware from './applyMiddleware.js';
export {
createStore,
bindActionCreators,
combineReducers,
applyMiddleware
}
1.createStore
是创建一个仓库,导出一个对象,对象拥有getState,dispatch,subscribe这三个key。。getState是用来获取state值,dispatch是用来派发执行reducers,subscribe是用来订阅。
工具函数用来判断是否是纯对象
function isPlainObject(obj){
if(typeof obj!=='object' || obj===null){
return false;
}
let proto =obj;
while(Object.getPrototypeOf(proto)){
proto=Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(obj)===proto;
}
reducer 函数必须是一个函数,它相当于处理器。用来合并修改state状态值。
action是一个对象,相当于动作行为。dispatch派发动作执行相应的reducer 处理器。createStore内部还实现了一个发布订阅的模式,订阅方:subscribe函数,发布方:在dispatch内部执行所收集的currentListeners数组。
import isPlainObject from '../utils/isPlainObject.js';
import ActionTypes from '../utils/actionTypes.js';
//reducer 是一个纯函数 preloadedState 是初始状态
export default function createStore(reducer,preloadedState){
if(typeof reducer !=='function'){
throw new Error('reducer必须是一个函数');
}
let currentState=preloadedState;//当前状态
let currentReducer=reducer;//当前处理器
let currentListeners=[];//定义一数组保存当前的监听函数
//用来获取状态值
function getState(){
return currentState;
}
//action {type:'xxx'};action是一个纯对象,必须拥有type属性
function dispatch(action){
if(!isPlainObject(action)){
throw new Error('action必须是一个纯函数');
}
if(typeof action.type==='undefined'){
throw new Error('action的type属性不能是undefined');
};
//将 初始的状态和action对象传递给reducer处理器
currentState=currentReducer(currentState,action);
//发布
for(let i=0;i<currentListeners.length;i++){
const listener=currentListeners[i];
listener();
}
return action;
}
//订阅函数
function subscribe(listener){
let subscribe=true; //开关用来优化数组
currentListeners.push(listener);
return function unsubscribe(){
if(!subscribed) return ;
const index=currentListeners.indexOf(listener);
currentListeners.splice(index,1);
subscribe=false;
}
}
//默认先执行一次dispatch函数,是为了将初始状态传递给reducer
dispatch({type:ActionTypes.INIT});
return {
getState,
dispatch,
subscribe
}
}
2、bindActionCreators
是用来将定义的action动作对象自动绑定到dispatch上进行派发。不需要手动去执行dispatch函数。
//此函数将原action函数进行重写
/*
action return { type:'xxx}
return dispatch( {type:'xxx'})
*/
//重写action函数
function bindActionCreator(actionCreator,dispatch){
return function(){
return dispatch(actionCreator.apply(this,arguments))
};
}
//返回一个已经将action的行为绑定在dispatch上的对象
export default function bindActionCreators(actionCreators,dispatch){
if(typeof actionCreator==='function'){
return bindActionCreator(actionCreators,dispatch);
}
const boundActionCreators={};
for(const key in actionCreators){
boundActionCreators[key]=bindActionCreator(actionCreators[key],dispatch);
}
return boundActionCreators;
}
3、combineReducers
是用来合并reducer,不同模块处理器可能不一样,为了只创建一个公共的仓库,即一个state状态。将不同模块的reducer处理器进行合并,返回合并后的state。
/*
将reducer进行合并,就是重写自己写的reducer处理器的过程返回合并后的state
*/
export default function(reducers){
const reducerKeys=Object.keys(reducers);
return function(state={},action){
const nextState={};
for(let i=0;i<reducerKeys.length;i++){
const key=reducerKeys[i];
const reducer=reducers[key];
const previousStateForKey=state[key];
//执行单个reducer,将初始状态传入。
const nextStateForKey=reducer(previousStateForKey,action);
nextState[key]=nextStateForKey;
}
return nextState;
}
}
4、applyMiddleware
是用来处理中间件的函数。其实就是将中间件进行合并处理,并且重写了createStore的dispatch函数。
工具函数:是用来合并函数,中间件的合并是由里到外。
function compose(...funcs){
return funcs.reduce((a,b)=>(...args)=>a(b(...args)))
}
//还可以有以下几种写法
function compose1(...funcs){
return function(...arg){
let result;
for(let i=funcs.length-1;i>=0;i--){
result=funcs[i](i==funcs.length-1?arg:result);
}
return result;
}
}
function compose3(...funcs){
return funcs.reduce((a,b)=>{
return (...args)=>{
return a(b(...args));
};
})
}
function compose4(...fns){
let args=arguments;
let start =args.length-1;
return function(){
let i=start;
let result =args[start].apply(this,arguments);
while(i--){
result=args[i].call(this,result);
}
return result;
}
}
import compose from './compose.js';
export default function applyMiddleware(...middlewares){ //middlewares=[logger1,logger2]
return function(createStore){
return function(reducer){
let store=createStore(reducer); //最开始的原生仓库
let dispatch=()=>{
throw Error('现在还不能用!');
}
let middlewareAPI={
getState:store.getState,
dispatch:(...args)=>{dispatch(...args)}
};
//chain =[logger1下第二层,logger2第二层]
const chain=middlewares.map(middleware=>middleware(middlewareAPI));
dispatch=compose(...chain)(store.dispatch);
return {
...store,
dispatch
}
}
}
}
thunk的源码解析
thunk还可以接收一个额外的参数,中间件的处理是由外到里。
function createThunkMiddleware(extraArgumrnt){
return ({dispatch,getState})=>next=>action=>{
if(typeof action === 'function'){
return action(dispatch,getState,extraArgumrnt)
}else{
next(action);
}
}
}
const thunk=createThunkMiddleware();
thunk.withExtraArgument=createThunkMiddleware;
export default thunk;