Vue3
生命周期实现原理
从零手写一.生命周期实现原理
定义生命周期类型 component.ts
export const enum LifecycleHooks {
BEFORE_MOUNT = 'bm',
MOUNTED = 'm',
BEFORE_UPDATE = 'bu',
UPDATED = 'u',
}
1
2
3
4
5
6
2
3
4
5
6
将对应的生命周期保存在实例上 apiLifecycle.ts
import { currentInstance, LifecycleHooks, setCurrentInstance } from "./component"
export function injectHook(type, hook, target) {
if (target) {
const hooks = target[type] || (target[type] = []); // 将生命周期保存在实例上
const wrappedHook = () =>{
setCurrentInstance(target); // 当生命周期调用时 保证currentInstance是正确的
hook.call(target);
setCurrentInstance(null);
}
hooks.push(wrappedHook);
}
}
export const createHook = (lifecycle) => (hook, target = currentInstance) => {
injectHook(lifecycle, hook, target)
}
// N个生命周期
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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
二.生命周期调用
shared.ts 获取每个fn执行
export const invokeArrayFns = (fns, arg?: any) => {
for (let i = 0; i < fns.length; i++) {
fns[i](arg)
}
}
1
2
3
4
5
2
3
4
5
instance.update = effect(function componentEffect() {
if (!instance.isMounted) {
const {bm, m , parent} = instance;
if(bm){ // beforeMount
invokeArrayFns(bm);
}
const proxyToUse = instance.proxy;
const subTree = (instance.subTree = instance.render.call(proxyToUse, proxyToUse));
patch(null, subTree, container);
initialVNode.el = subTree.el; // 组件的el和子树的el是同一个
instance.isMounted = true; // 组件已经挂载完毕
if(m){ // mounted
queuePostFlushCb(m)
}
} else {
const prevTree = instance.subTree;
const proxyToUse = instance.proxy;
const {bu,u} = instance;
if(bu){ // beforeUpdate
invokeArrayFns(bu);
}
const nextTree = instance.render.call(proxyToUse, proxyToUse); // 在来一次
if(u){ // updated
queuePostFlushCb(u);
}
instance.subTree = nextTree
patch(prevTree, nextTree, container);
}
}, {
scheduler: queueJob
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
在完成渲染后执行生命周期钩子
export function queuePostFlushCb(cb) { // cb 可能是一个数组
queueCb(cb, pendingPostFlushCbs)
}
function queueCb(cb, pendingQueue) {
if(!isArray(cb)){
pendingQueue.push(cb);
}else{
pendingQueue.push(...cb);
}
queueFlush();
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11