Redux源码分析–Enhancer

  • Post author:
  • Post category:其他



Redux源码分析:

store enhancer翻译成中文是store增强器,store middleware实质也是一种enhancer的实现,store middleware增强的dispatch的功能。store enhancer的实现不仅仅是丰富dispatch作用,你也可以通过createStore(reducer, preloadedState, enhancer)创建的store对象新增新的方法等等

在Redux源码中,涉及到enhancer的代码非常少,就仅仅几行。前面的判断都是对createStore传参进行判断:1、如果第二个参数preloadedState为函数,第三个没有传,那将enhancer = preloadedState, preloadedState = undefined 2、enhancer不能有多个,有且一个。如果都满足的话,enhancer又存在,执行enhancer(createStore)(reducer, preloadedState),enhancer函数的内部内容,自己去实现

通过enhancer(createStore)(reducer, preloadedState)来确定enhancer的实现模型是:


(createStore) => (reducer, preloaderState) => {}

如果想进行多个enhancer,怎么样呢,这就需要用到我们之前介绍的compose了,compose功能是将多个函数,合并成一个函数,就满足了createStore的要求了。如果你想了解compose,请跳转至

Redux源码分析–compose

if (
    (typeof preloadedState === 'function' && typeof enhancer === 'function') ||
    (typeof enhancer === 'function' && typeof arguments[3] === 'function')
  ) {
    throw new Error(
      'It looks like you are passing several store enhancers to ' +
        'createStore(). This is not supported. Instead, compose them ' +
        'together to a single function.'
    )
  }

  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }

下面我们举例来说明:

比如你想要用enhancer来实现一个state改变前改变后日志:

let enhanncer = (createStore) => (reducer, preloadedState) => {
	let store = createStore(reducer, preloadedState);

	let dispatch = (action) => {
		//dispatch(action)之前state的值
		console.log('before: ', store.getState());

		store.dispatch(action);

		//dispatch(action)之后state的值
		console.log('after: ', store.getState());

		return action;

	}

	return {
		...store,
		dispatch
	}
}

let store = createStore(reducer, enhancer);

如果有多个enhancer,怎么实现呢?

使用compose将其组合成一个函数,如下实例:

let e1 = (createStore) => (reducer, preloadedState) => {
	console.log('e1: ', createStore);
	let store = createStore(reducer, preloadedState);
	console.log('e1-after');

	return {
		...store
	}
}

let e2 = (createStore) => (reducer, preloadedState) => {
	console.log('e2: ', createStore);
	let store = createStore(reducer, preloadedState);
	console.log('e2-after');

	return {
		...store
	}
}

let e3 = (createStore) => (reducer, preloadedState) => {
	console.log('e3: ', createStore);
	let store = createStore(reducer, preloadedState);
	console.log('e3-after');

	return {
		...store
	}
}
  
let enhancer = compose(e1, e2, e3);

let store = createStore(reducer, enhancer);

运行结果:

从上述结果可以分析可以看出:当进行多个enhancer(增强器)时,使用compose合并成一个enhancer,一系列的enhancer运行前后,compose从左到右依次运行,当执行某个enhancer时,如果执行到(createStore) => {}中的createStore(reducer,preloadedState)时,执行转到下一个enhancer,因为当前的createStore不是真正的createStore(),而是下一个enhancer的(reducer,preloadedState) => {}。当执行到最右边的enhancer,在反向往最左边依次执行,就如结果显示的一样,

e1 e2 e3 e3-after e2-after e1-after

enhancer和middleware怎么转换呢?

本质上middleware其实就是一个enhancer,只不过middleware只是在丰富dispatch,那么我们怎么把middleware转换成enhancer来使用呢?

compose(enhancer1, enhancer2, applyMiddleware(middleware1, middleware2))

当异步和同步middleware同时进行时,位置该如何存放呢?

异步功能的middleware存放在applyMiddleware的最右边,因为如果放在其他位置,可能对于其右边的middleware会不起作用。

当middleware和enhancer都存在的时候,代码的执行顺序是怎么样呢?

你可以这样理解:因为enhancer是增强store功能,肯定是在dispatch(action)之前运行,即代码初始阶段,而Middleware是需要action,才能执行(action) => {},所以middleware中的(action) => {}代码才晚于enhancer。

源码分析如下:

1、根据let store = applyMiddleware(m1, m2, m3)(createStore)(reducer, preloadedState, compose(e1, e2, e3)),那么代码应该先执行applyMiddleware()方法,由于applyMiddleware方法第一行执行了createStore(…args),则接着去执行compose(e1, e2, e3)(createStore)(reducer, preloadedState),即先处理enhancer,处理完,在进行Middleware的处理(它的处理需要dispatch(action)),下面用实例来说明:

let e1 = (createStore) => (reducer, preloadedState) => {
	console.log('e1');
	let store = createStore(reducer, preloadedState);
	console.log('e1-after');

	return {
		...store
	}
}

let e2 = (createStore) => (reducer, preloadedState) => {
	console.log('e2');
	let store = createStore(reducer, preloadedState);
	console.log('e2-after');

	return {
		...store
	}
}

let e3 = (createStore) => (reducer, preloadedState) => {
	console.log('e3');
	let store = createStore(reducer, preloadedState);
	console.log('e3-after');

	return {
		...store
	}
}

let m1 = ({getState, dispatch}) => (next) => (action) => {
	console.log('m1');
	next(action);
	console.log('m1-after');
}

let m2 = ({getState, dispatch}) => (next) => (action) => {
	console.log('m2');
	next(action);
	console.log('m2-after');
}

let m3 = ({getState, dispatch}) => (next) => (action) => {
	console.log('m3');
	next(action);
	console.log('m3-after');
}
  
let enhancer = compose(e1, e2, e3);

let store = applyMiddleware(m1, m2, m3)(createStore)(reducer, enhancer);

执行结果:e1 e2 e3 e3-after e2-after e1-after 当触发action之后,打印出:m1 m2 m3 m3-after m2-after m1-after

2、当let store = createStore(reducer, preloadedState, compose(e1, e2, e3, applyMiddleware(m1, m2, m3)))时,执行结果一样。

如果在middleware中,又进行了dispatch(action),那middleware执行顺序如何

这种情况是针对异步情况,比如异步ajax请求。下面我们模拟这种情况,不过你在middleware中不能直接使用dispatch(action),如果直接使用,可能会产生死循环。因此在middleware中使用dispatch(action)时,要有一个条件判断,满足这个条件的,才能进行dispatch(action),要是无限满足,那就死循环了。

先进行一个实例:

let m1 = ({getState, dispatch}) => (next) => (action) => {
	console.log('m1-next-before');
	next(action);
	console.log('m1-next-after');
}

let m2 = ({getState, dispatch}) => (next) => (action) => {
	console.log('m2-next-before');
	//当执行dispatch(action)时(保证isNotGo不为true),执行到此处时,会再次执行dispatch({type: 'CHESHI', isNotGo: true})
	//不这样设置,可能会造成死循环
	if(!action.isNotGo) {
		dispatch({type: 'CHESHI', isNotGo: true});
	}	
	next(action);
	console.log('m2-next-after');
}

let m3 = ({getState, dispatch}) => (next) => (action) => {
	console.log('m3-next-before');
	next(action);
	console.log('m3-next-after');
}

let store = applyMiddleware(m1, m2, m3)(createStore)(reducer);

触发dispatch(action)后,结果:

从实例中看出,当触发dispatch(action)时,执行m1-next-before,当运行到中间件m2时,输出m2-next-before,此时

判断出!action.isNotGo为true,会进行dispatch(action),程序将再次从m1开始,依次执行,等再次到m2时,!action.isNotGo

为false,不会再dispatch(action)了,则将执行到m3,即此时,结果应该是m1-next-before m2-next-before  m1-next-before

m2-next-before m3-next-before m3-next-after m2-next-after m1-next-after,接着将继续从m2开始执行next(action),

输出:m3-next-before m3-next-after m2-next-after m1-next-after



版权声明:本文为wangyuegyq原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。