reecho
Version:
Reecho 是一款基于依赖收集的MVVM框架,它具有以下特点 - 声明式数据: 基于proxy的依赖收集 - 使用函数定义组件,但组件不会如React一样重复执行造成心智负担 - 读写分离,读取状态和更改状态统一使用函数,避免vue3的ref一样有时需要`xxx.value`有时不需要的不一致性 - 使用TS编写,类型友好
100 lines (88 loc) • 2.57 kB
text/typescript
import {
setCurrentInstance,
currentInstance,
ComponentInstance,
} from "./components";
import { isFunction, isPromise } from "../shared";
export const enum LifecycleHooks {
BEFORE_MOUNT = "bm",
MOUNTED = "m",
BEFORE_UPDATE = "bu",
UPDATED = "u",
BEFORE_UNMOUNT = "bum",
UNMOUNTED = "um",
RENDER_TRIGGERED = "rtg",
RENDER_TRACKED = "rtc",
ERROR_CAPTURED = "ec",
}
export const injectLifeCycleHook = <T extends Function = () => {}>(
type: LifecycleHooks,
hook: T,
target: ComponentInstance | null = currentInstance
) => {
if (target) {
let hooks: Function[];
// 将生命周期绑定在组件实例上
if (target[type]) {
hooks = target[type];
} else {
hooks = target[type] = [];
}
const wrappedHook = (...args: unknown[]) => {
// TODO 考虑在effect中调用生命周期钩子的情况,需要暂停依赖收集
setCurrentInstance(target);
// 执行传入的hook函数并捕获错误
const res = callWithAsyncErrorHandling(hook, target, type, args);
setCurrentInstance(null);
return res;
};
hooks.push(wrappedHook);
return wrappedHook;
}
};
export const createHook = <T extends Function = () => {} | void>(
lifecycle: LifecycleHooks
) => (hook: T, target: ComponentInstance | null = currentInstance) =>
injectLifeCycleHook(lifecycle, hook, target);
export const onBeforeMount = createHook(LifecycleHooks.BEFORE_MOUNT);
export const onMounted = createHook(LifecycleHooks.MOUNTED);
export const onBeforeUpdate = createHook(LifecycleHooks.BEFORE_UPDATE);
export const onUpdated = createHook(LifecycleHooks.UPDATED);
export const onBeforeUnmount = createHook(LifecycleHooks.BEFORE_UNMOUNT);
export const onUnmounted = createHook(LifecycleHooks.UNMOUNTED);
// 异步错误捕获
const callWithAsyncErrorHandling = (
fn: Function | Function[],
instance: ComponentInstance | null,
type: any,
args: any[]
): any[] => {
if (isFunction(fn)) {
// 传入一个函数
let res: any;
try {
res = args ? fn(...args) : fn();
if (res && isPromise(res)) {
// 说明是异步的
res.catch((err) => {
handleError(err);
});
}
} catch (err) {
handleError(err);
}
return res;
} else {
// 传入函数数组
let ret = [];
for (let i = 0; i < fn.length; i++) {
const f = fn[i];
ret.push(callWithAsyncErrorHandling(f, instance, type, args));
}
return ret;
}
};
// 错误处理函数
const handleError = (err: Error) => {
throw err;
};