112 lines
3.4 KiB
TypeScript
112 lines
3.4 KiB
TypeScript
/**
|
||
* @author dbkillerf6
|
||
* @since 2020-04-10
|
||
*/
|
||
|
||
import { cloneDeep } from 'lodash';
|
||
import type { OnGlobalStateChangeCallback, MicroAppStateActions } from './interfaces';
|
||
|
||
let globalState: Record<string, any> = {};
|
||
|
||
const deps: Record<string, OnGlobalStateChangeCallback> = {};
|
||
|
||
// 触发全局监听
|
||
function emitGlobal(state: Record<string, any>, prevState: Record<string, any>) {
|
||
Object.keys(deps).forEach((id: string) => {
|
||
if (deps[id] instanceof Function) {
|
||
deps[id](cloneDeep(state), cloneDeep(prevState));
|
||
}
|
||
});
|
||
}
|
||
|
||
export function initGlobalState(state: Record<string, any> = {}) {
|
||
if (process.env.NODE_ENV === 'development') {
|
||
console.warn(`[qiankun] globalState tools will be removed in 3.0, pls don't use it!`);
|
||
}
|
||
|
||
if (state === globalState) {
|
||
console.warn('[qiankun] state has not changed!');
|
||
} else {
|
||
const prevGlobalState = cloneDeep(globalState);
|
||
globalState = cloneDeep(state);
|
||
emitGlobal(globalState, prevGlobalState);
|
||
}
|
||
return getMicroAppStateActions(`global-${+new Date()}`, true);
|
||
}
|
||
|
||
export function getMicroAppStateActions(id: string, isMaster?: boolean): MicroAppStateActions {
|
||
return {
|
||
/**
|
||
* onGlobalStateChange 全局依赖监听
|
||
*
|
||
* 收集 setState 时所需要触发的依赖
|
||
*
|
||
* 限制条件:每个子应用只有一个激活状态的全局监听,新监听覆盖旧监听,若只是监听部分属性,请使用 onGlobalStateChange
|
||
*
|
||
* 这么设计是为了减少全局监听滥用导致的内存爆炸
|
||
*
|
||
* 依赖数据结构为:
|
||
* {
|
||
* {id}: callback
|
||
* }
|
||
*
|
||
* @param callback
|
||
* @param fireImmediately
|
||
*/
|
||
onGlobalStateChange(callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) {
|
||
if (!(callback instanceof Function)) {
|
||
console.error('[qiankun] callback must be function!');
|
||
return;
|
||
}
|
||
if (deps[id]) {
|
||
console.warn(`[qiankun] '${id}' global listener already exists before this, new listener will overwrite it.`);
|
||
}
|
||
deps[id] = callback;
|
||
if (fireImmediately) {
|
||
const cloneState = cloneDeep(globalState);
|
||
callback(cloneState, cloneState);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* setGlobalState 更新 store 数据
|
||
*
|
||
* 1. 对输入 state 的第一层属性做校验,只有初始化时声明过的第一层(bucket)属性才会被更改
|
||
* 2. 修改 store 并触发全局监听
|
||
*
|
||
* @param state
|
||
*/
|
||
setGlobalState(state: Record<string, any> = {}) {
|
||
if (state === globalState) {
|
||
console.warn('[qiankun] state has not changed!');
|
||
return false;
|
||
}
|
||
|
||
const changeKeys: string[] = [];
|
||
const prevGlobalState = cloneDeep(globalState);
|
||
globalState = cloneDeep(
|
||
Object.keys(state).reduce((_globalState, changeKey) => {
|
||
if (isMaster || _globalState.hasOwnProperty(changeKey)) {
|
||
changeKeys.push(changeKey);
|
||
return Object.assign(_globalState, { [changeKey]: state[changeKey] });
|
||
}
|
||
console.warn(`[qiankun] '${changeKey}' not declared when init state!`);
|
||
return _globalState;
|
||
}, globalState),
|
||
);
|
||
if (changeKeys.length === 0) {
|
||
console.warn('[qiankun] state has not changed!');
|
||
return false;
|
||
}
|
||
emitGlobal(globalState, prevGlobalState);
|
||
return true;
|
||
},
|
||
|
||
// 注销该应用下的依赖
|
||
offGlobalStateChange() {
|
||
delete deps[id];
|
||
return true;
|
||
},
|
||
};
|
||
}
|