forked from Lucifier129/react-lite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReactDOM.js
124 lines (112 loc) · 3.35 KB
/
ReactDOM.js
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
import * as _ from './util'
import {
COMPONENT_ID,
VELEMENT,
VCOMPONENT,
ELEMENT_NODE_TYPE,
DOC_NODE_TYPE,
DOCUMENT_FRAGMENT_NODE_TYPE
} from './constant'
import { initVnode, destroyVnode, clearPending, compareTwoVnodes } from './virtual-dom'
import { updateQueue } from './Component'
function isValidContainer(node) {
return !!(node && (
node.nodeType === ELEMENT_NODE_TYPE ||
node.nodeType === DOC_NODE_TYPE ||
node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
))
}
let pendingRendering = {}
let vnodeStore = {}
function renderTreeIntoContainer(vnode, container, callback, parentContext) {
if (!vnode.vtype) {
throw new Error(`cannot render ${ vnode } to container`)
}
if (!isValidContainer(container)) {
throw new Error(`container ${container} is not a DOM element`)
}
let id = container[COMPONENT_ID] || (container[COMPONENT_ID] = _.getUid())
let argsCache = pendingRendering[id]
// component lify cycle method maybe call root rendering
// should bundle them and render by only one time
if (argsCache) {
if (argsCache === true) {
pendingRendering[id] = argsCache = { vnode, callback, parentContext }
} else {
argsCache.vnode = vnode
argsCache.parentContext = parentContext
argsCache.callback = argsCache.callback ? _.pipe(argsCache.callback, callback) : callback
}
return
}
pendingRendering[id] = true
let oldVnode = null
let rootNode = null
if (oldVnode = vnodeStore[id]) {
rootNode = compareTwoVnodes(oldVnode, vnode, container.firstChild, parentContext)
} else {
rootNode = initVnode(vnode, parentContext, container.namespaceURI)
var childNode = null
while (childNode = container.lastChild) {
container.removeChild(childNode)
}
container.appendChild(rootNode)
}
vnodeStore[id] = vnode
let isPending = updateQueue.isPending
updateQueue.isPending = true
clearPending()
argsCache = pendingRendering[id]
delete pendingRendering[id]
let result = null
if (typeof argsCache === 'object') {
result = renderTreeIntoContainer(argsCache.vnode, container, argsCache.callback, argsCache.parentContext)
} else if (vnode.vtype === VELEMENT) {
result = rootNode
} else if (vnode.vtype === VCOMPONENT) {
result = rootNode.cache[vnode.uid]
}
if (!isPending) {
updateQueue.isPending = false
updateQueue.batchUpdate()
}
if (callback) {
callback.call(result)
}
return result
}
export function render(vnode, container, callback) {
return renderTreeIntoContainer(vnode, container, callback)
}
export function unstable_renderSubtreeIntoContainer(parentComponent, subVnode, container, callback) {
let context = parentComponent.$cache.parentContext
return renderTreeIntoContainer(subVnode, container, callback, context)
}
export function unmountComponentAtNode(container) {
if (!container.nodeName) {
throw new Error('expect node')
}
let id = container[COMPONENT_ID]
let vnode = null
if (vnode = vnodeStore[id]) {
destroyVnode(vnode, container.firstChild)
container.removeChild(container.firstChild)
delete vnodeStore[id]
return true
}
return false
}
export function findDOMNode(node) {
if (node == null) {
return null
}
if (node.nodeName) {
return node
}
let component = node
// if component.node equal to false, component must be unmounted
if (component.getDOMNode && component.$cache.isMounted) {
return component.getDOMNode()
}
throw new Error('findDOMNode can not find Node')
}