相信你们都知道Redux的middleware(中间件)的概念,Redux经过middleware能够完成发送异步action(网络请求)、打印action的日志等功能。相对而言,Redux的store enhancer的概念,不少人并非很清楚。前端
Redux经过API createStore建立store,createStore的函数签名以下:git
createStore(reducer, [preloadedState], [enhancer])
复制代码
其中,第3个可选参数enhancer,就是指的store enhancer。github
store enhancer,能够翻译成store的加强器,顾名思义,就是加强store的功能。一个store enhancer,实际上就是一个高阶函数,它的参数是建立store的函数(store creator),返回值是一个能够建立功能更增强大的store的函数(enhanced store creator),这和React中的高阶组件的概念很类似。redux
store enhancer 函数的结构通常以下:bash
function enhancerCreator() {
return createStore => (...args) => {
// do something based old store
// return a new enhanced store
}
}
复制代码
注意,enhancerCreator是用于建立store enhancer 的函数,也就是说enhancerCreator的执行结果才是一个store enhancer。(…args) 参数表明建立store所需的参数,也就是createStore接收的参数,实际上就是(reducer, [preloadedState], [enhancer])。网络
如今,咱们来建立一个store enhancer,用于输出发送的action的信息和state的变化:app
// autoLogger.js
// store enhancer
export default function autoLogger() {
return createStore => (reducer, initialState, enhancer) => {
const store = createStore(reducer, initialState, enhancer)
function dispatch(action) {
console.log(`dispatch an action: ${JSON.stringify(action)}`);
const res = store.dispatch(action);
const newState = store.getState();
console.log(`current state: ${JSON.stringify(newState)}`);
return res;
}
return {...store, dispatch}
}
}
复制代码
autoLogger() 改变了store dispatch的默认行为,在每次发送action先后,都会输出日志信息。而后在建立store上,使用autoLogger()这个store enhancer:异步
// configureStore.js
import { createStore, applyMiddleware } from 'redux';
import rootReducer from 'path/to/reducers';
import autLogger from 'path/to/autoLogger';
const store = createStore(
reducer,
autoLogger()
);
复制代码
若是你了解redux-logger这个redux middleware,是否是感受autoLogger()的做用和它很类似呢?难道store enhancer 和 middleware 能够实现相同的功能?确实如此。实际上,middleware的实现函数applyMiddleware自己就是一个store enhancer,applyMiddleware源码示意以下:函数
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
// 省略
return {
...store,
dispatch
}
}
}
复制代码
applyMiddleware的结构和前面提到的store enhancer的结构彻底相同,applyMiddleware(...middlewares)的执行结果就是一个store enhancer。因此,能够用middleware实现的功能,固然也可使用store enhancer 来实现了。从applyMiddleware(...middlewares)最终的返回结构{...store, dispatch}还能够推测出,applyMiddleware(...middlewares)这个store enhancer 主要用来修改store的dispatch方法,这也确实是middleware的做用:加强store的dispatch功能。middleware其实是在applyMiddleware(...middlewares) 这个store enhancer之上的一层抽象,applyMiddleware(...middlewares) 传递给每个middleware参数{getState, dispatch},middleware对dispatch方法进行增强。ui
当同时使用applyMiddleware(...middlewares)和其余store enhancer时,每每能够先使用redux提供的compose函数,将这些store enhancer组合成一个:
// configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from 'path/to/reducers';
import autLogger from 'path/to/autoLogger';
const enhancer = compose(
applyMiddleware(...middlewares),
autLogger()
);
const store = createStore(
reducer,
enhancer
);
复制代码
通过compose组合后,全部的store enhancer会造成一个洋葱模型,compose中的第一个enhancer处于洋葱模型的最外层,最后一个enhancer处于洋葱模型的最内层,每当发送一个action,都会通过洋葱模型从外到内的每一层enhancer的处理,以下图所示。由于通常咱们经过middleware处理异步action,为保证其余enhancer接收到的都是普通action,因此须要将applyMiddleware(...middlewares)做为第一个store enhancer 传给 compose,让全部的action先通过applyMiddleware(...middlewares)的处理。
applyMiddleware(…middlewares)将middleware限制为只能够加强store dispatch的功能,但这只是它自身的规范限制,对于其余store enhancer,你能够加强store中包含的任意方法的功能,如dispatch、subscribe、getState、replaceReducer等。毕竟,store只是一个包含一些函数的普通JavaScript对象,能够很容易的复制其中的方法,并增长新的功能。
咱们再来看一个例子,redux-localstorage, 这个store enhancer 用来自动将store中的state持久化到localStorage中。它的主要代码以下:
// store enhancer
export default function persistState(paths, config) {
// 一些功能选项配置
return next => (reducer, initialState, enhancer) => {
let persistedState
let finalInitialState
try {
persistedState = deserialize(localStorage.getItem(key))
finalInitialState = merge(initialState, persistedState)
} catch (e) {
console.warn('Failed to retrieve initialize state from localStorage:', e)
}
const store = next(reducer, finalInitialState, enhancer)
const slicerFn = slicer(paths)
// 主要代码
store.subscribe(function () {
const state = store.getState()
const subset = slicerFn(state)
try {
localStorage.setItem(key, serialize(subset))
} catch (e) {
console.warn('Unable to persist state to localStorage:', e)
}
})
return store
}
}
复制代码
这个enhancer作的事情其实很简单,只是在建立store后,当即订阅了store的变化,当store中的state发生变化时,将state持久化到localStorage。
由于store enhancer中,咱们能够任意复制、改变store中的方法,因此在自定义store enhancer时,有可能会由于破坏了Redux的正常工做流,致使整个应用没法正常工做。下面就是一个破坏性enhancer的例子:
export default function breakingEnhancer() {
return createStore => (reducer, initialState, enhancer) => {
const store = createStore(reducer, initialState, enhancer)
function dispatch(action) {
console.log(`dispatch an action: ${JSON.stringify(action)}`);
console.log(`current state: ${JSON.stringify(newState)}`);
return res;
}
return {...store, dispatch}
}
}
复制代码
这个例子从新建立了一个dispatch方法,但在新的dispatch方法中,并无调用老的dispatch方法,将action发送出去,致使action没法正常发送,整个应用天然也就没法工做。因此,自定义store enhancer时,必定要注意,不要破坏了Redux的原有工做流。
欢迎关注个人公众号:老干部的大前端,领取21本大前端精选书籍!