/
unmounting.ts
143 lines (127 loc) · 3.84 KB
/
unmounting.ts
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import {
isArray,
isFunction,
isInvalid,
isNull,
isNullOrUndef,
isObject,
LifecycleClass,
throwError
} from 'inferno-shared';
import VNodeFlags from 'inferno-vnode-flags';
import options from '../core/options';
import { VNode, InfernoChildren, Ref } from '../core/VNodes';
import {
patchEvent
} from './patching';
import {
poolComponent,
poolElement
} from './recycling';
import { componentToDOMNodeMap } from './rendering';
import { removeChild } from './utils';
export function unmount(vNode: VNode, parentDom: Element, lifecycle: LifecycleClass, canRecycle: boolean, isRecycling: boolean) {
const flags = vNode.flags;
if (flags & VNodeFlags.Component) {
unmountComponent(vNode, parentDom, lifecycle, canRecycle, isRecycling);
} else if (flags & VNodeFlags.Element) {
unmountElement(vNode, parentDom, lifecycle, canRecycle, isRecycling);
} else if (flags & (VNodeFlags.Text | VNodeFlags.Void)) {
unmountVoidOrText(vNode, parentDom);
}
}
function unmountVoidOrText(vNode: VNode, parentDom: Element) {
if (parentDom) {
removeChild(parentDom, vNode.dom);
}
}
export function unmountComponent(vNode: VNode, parentDom: Element, lifecycle: LifecycleClass, canRecycle: boolean, isRecycling: boolean) {
const instance = vNode.children as any;
const flags = vNode.flags;
const isStatefulComponent = flags & VNodeFlags.ComponentClass;
const ref = vNode.ref as any;
const dom = vNode.dom;
if (!isRecycling) {
if (isStatefulComponent) {
if (!instance._unmounted) {
instance._ignoreSetState = true;
options.beforeUnmount && options.beforeUnmount(vNode);
instance.componentWillUnmount && instance.componentWillUnmount();
if (ref && !isRecycling) {
ref(null);
}
instance._unmounted = true;
options.findDOMNodeEnabled && componentToDOMNodeMap.delete(instance);
const subLifecycle = instance._lifecycle;
unmount(instance._lastInput, null, subLifecycle, false, isRecycling);
}
} else {
if (!isNullOrUndef(ref)) {
if (!isNullOrUndef(ref.onComponentWillUnmount)) {
ref.onComponentWillUnmount(dom);
}
}
unmount(instance, null, lifecycle, false, isRecycling);
}
}
if (parentDom) {
let lastInput = instance._lastInput;
if (isNullOrUndef(lastInput)) {
lastInput = instance;
}
removeChild(parentDom, dom);
}
if (options.recyclingEnabled && !isStatefulComponent && (parentDom || canRecycle)) {
poolComponent(vNode);
}
}
export function unmountElement(vNode: VNode, parentDom: Element, lifecycle: LifecycleClass, canRecycle: boolean, isRecycling: boolean) {
const dom = vNode.dom;
const ref = vNode.ref as any;
const events = vNode.events;
if (ref && !isRecycling) {
unmountRef(ref);
}
const children = vNode.children;
if (!isNullOrUndef(children)) {
unmountChildren(children, lifecycle, isRecycling);
}
if (!isNull(events)) {
for (let name in events) {
// do not add a hasOwnProperty check here, it affects performance
patchEvent(name, events[name], null, dom);
events[name] = null;
}
}
if (parentDom) {
removeChild(parentDom, dom);
}
if (options.recyclingEnabled && (parentDom || canRecycle)) {
poolElement(vNode);
}
}
function unmountChildren(children: InfernoChildren, lifecycle: LifecycleClass, isRecycling: boolean) {
if (isArray(children)) {
for (let i = 0, len = (children as Array<string | number | VNode>).length; i < len; i++) {
const child = children[i];
if (!isInvalid(child) && isObject(child)) {
unmount(child as VNode, null, lifecycle, false, isRecycling);
}
}
} else if (isObject(children)) {
unmount(children as VNode, null, lifecycle, false, isRecycling);
}
}
function unmountRef(ref: Ref) {
if (isFunction(ref)) {
ref(null);
} else {
if (isInvalid(ref)) {
return;
}
if (process.env.NODE_ENV !== 'production') {
throwError('string "refs" are not supported in Inferno 1.0. Use callback "refs" instead.');
}
throwError();
}
}