plugin
概述
plugin 是 redux-saga 内部处理 hooks 的,主要在 core.create() 方法里面使用。
源码位置
dva/packages/dva-core/src/Plugin.js
解析
Plugin
Plugin.js 文件默认导出一个 Plugin 类
- 在 constructor 里面定义了 _handleActions 和 hooks 属性,hooks 是一个对象,key 是所有的 hooks 值为一个数组
- 接下来实现了三个方法 use apply 和 get,我们将在下面讲解
const hooks = [
'onError',
'onStateChange',
'onAction',
'onHmr',
'onReducer',
'onEffect',
'extraReducers',
'extraEnhancers',
'_handleActions',
];
export default class Plugin {
constructor() {
this._handleActions = null;
this.hooks = hooks.reduce((memo, key) => {
memo[key] = [];
return memo;
}, {});
}
use(plugin) {
// ......
}
apply(key, defaultHandler) {
// ......
}
get(key) {
// ......
}
}
use
use 方法是 app.use(hooks) 的内部实现,如果你看了 core.create() 这篇你就会知道,它的作用是配置 hooks,接下来我们就来看一下它的内部实现。
- 首先通过 isPlainObject 判断 plugin 是否是一个纯对象(通过 Object constructor 创建的)
- 遍历 plugin 对象,如果 key 是 plugin 自身的属性就对 key 值分别进行判断
key === '_handleActions'
: 给 this._handleActions 赋值key === 'extraEnhancers'
: 将新的 extraEnhancers 覆盖掉原有的- 其它情况将 plugin push 到对应的数组里
use(plugin) {
invariant(
isPlainObject(plugin),
'plugin.use: plugin should be plain object'
);
const hooks = this.hooks;
for (const key in plugin) {
if (Object.prototype.hasOwnProperty.call(plugin, key)) {
invariant(hooks[key], `plugin.use: unknown plugin property: ${key}`);
if (key === '_handleActions') {
this._handleActions = plugin[key];
} else if (key === 'extraEnhancers') {
hooks[key] = plugin[key];
} else {
hooks[key].push(plugin[key]);
}
}
}
}
apply
apply 会返回一个函数,这个函数会执行所有 onError 或 onHmr 的处理函数,这个方法只在内部使用。
- 首先校验 key 是否属于 onError 和 onHmr
- 获取对应的 hooks 数组 fns
- 返回一个匿名方法,里面判断 fns 如果不为空的话就依次调用其中的方法,如果不为空的调用 apply 传递进来的 defaultHandler
apply(key, defaultHandler) {
const hooks = this.hooks;
const validApplyHooks = ['onError', 'onHmr'];
invariant(
validApplyHooks.indexOf(key) > -1,
`plugin.apply: hook ${key} cannot be applied`
);
const fns = hooks[key];
return (...args) => {
if (fns.length) {
for (const fn of fns) {
fn(...args);
}
} else if (defaultHandler) {
defaultHandler(...args);
}
};
}
get
get 用于根据传入的 key 获取对应的 hooks,主要在 [core.create()] 方法里面调用。
- 首先校验 key 是否属于 hooks 里面的属性,然后对 key 分别做判断
key === 'extraReducers'
: 调用 getExtraReducers 下面会介绍key === 'onReducer'
: 调用 getOnReducer 下面会介绍- 其它情况直接返回对应的 hooks
get(key) {
const hooks = this.hooks;
invariant(key in hooks, `plugin.get: hook ${key} cannot be got`);
if (key === 'extraReducers') {
return getExtraReducers(hooks[key]);
} else if (key === 'onReducer') {
return getOnReducer(hooks[key]);
} else {
return hooks[key];
}
}
getExtraReducers
getExtraReducers 将 hooks['extraReducers'] 里面保存的对象数组延展成一个一维对象并返回。
function getExtraReducers(hook) {
let ret = {};
for (const reducerObj of hook) {
ret = { ...ret, ...reducerObj };
}
return ret;
}
getOnReducer
返回一个方法,这个方法将所有 hook 里面的 reducerEnhancer 链式调用,最终返回的方法接受一个 reducer,返回链式调用的那个方法。 举个例子:
const hook = [rn1, rn2, rn3];
getOnReducer(hook)
// 返回的结果是:(reducer) => rn3(rn2(rn1(reducer)))
function getOnReducer(hook) {
return function(reducer) {
for (const reducerEnhancer of hook) {
reducer = reducerEnhancer(reducer);
}
return reducer;
};
}
filterHooks
plugin.js 文件还对外暴露了一个 filterHooks 方法,见名知意它的作用就是对传入的 hooks 进行筛选,只有在 dva 规定的 hooks 列表中才会将其返回。
export function filterHooks(obj) {
return Object.keys(obj).reduce((memo, key) => {
if (hooks.indexOf(key) > -1) {
memo[key] = obj[key];
}
return memo;
}, {});
}