Skip to content

Commit b100f83

Browse files
committed
fix: nerv-devtools can't create vnode recursively
1 parent 4a22175 commit b100f83

File tree

1 file changed

+47
-42
lines changed

1 file changed

+47
-42
lines changed

packages/nerv-devtools/src/devtools.ts

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
// tslint:disable-next-line:no-var-requires
22
import { options } from 'nervjs'
3-
4-
options.debug = true
5-
3+
import { isComposite, isWidget, isVText, isValidElement } from 'nerv-shared'
4+
const isArray = Array.isArray
65
/**
76
* Return a ReactElement-compatible object for the current state of a Nerv
87
* component.
98
*/
10-
function createReactElement (component) {
9+
function createReactElement (vnode) {
1110
return {
12-
type: component.__proto__.constructor,
13-
key: component.key,
11+
type: vnode.type,
12+
key: vnode.key,
1413
ref: null,
15-
props: component.props
14+
props: vnode.props
15+
}
16+
}
17+
18+
function normalizeChildren (children) {
19+
if (isArray(children)) {
20+
return children.filter(isValidElement).map(updateReactComponent)
21+
} else {
22+
return isValidElement(children) ? [updateReactComponent(children)] : []
1623
}
1724
}
1825

@@ -26,26 +33,19 @@ function createReactElement (component) {
2633
*
2734
* @param {Node} node
2835
*/
29-
function createReactDOMComponent (node) {
30-
const childNodes =
31-
node.nodeType === Node.ELEMENT_NODE ? Array.from(node.childNodes) : []
32-
const isText = node.nodeType === Node.TEXT_NODE
36+
function createReactDOMComponent (vnode) {
37+
const isText = isVText(vnode)
3338

3439
return {
3540
// --- ReactDOMComponent interface
3641
_currentElement: isText
37-
? node.textContent
42+
? vnode.text
3843
: {
39-
type: node.nodeName.toLowerCase(),
40-
props: node._props
44+
type: vnode.type,
45+
props: normalizeProps(vnode.props)
4146
},
42-
_renderedChildren: childNodes.map((child: any) => {
43-
if (child._component) {
44-
return updateReactComponent(child._component)
45-
}
46-
return updateReactComponent(child)
47-
}),
48-
_stringText: isText ? node.textContent : null,
47+
_renderedChildren: normalizeChildren(vnode.children),
48+
_stringText: isText ? vnode.text : null,
4949

5050
// --- Additional properties used by Nerv devtools
5151

@@ -54,7 +54,7 @@ function createReactDOMComponent (node) {
5454
// This is used to send the appropriate notifications when DOM components
5555
// are added or updated between composite component updates.
5656
_inDevTools: false,
57-
node
57+
node: !isText ? vnode.dom : null
5858
}
5959
}
6060

@@ -70,6 +70,12 @@ function typeName (element) {
7070
return element.type
7171
}
7272

73+
function normalizeProps (_props) {
74+
const props = { ..._props }
75+
delete props.owner
76+
return props
77+
}
78+
7379
/**
7480
* Return a ReactCompositeComponent-compatible object for a given Nerv
7581
* component instance.
@@ -81,19 +87,21 @@ function typeName (element) {
8187
* See https://github.com/facebook/react-devtools/blob/e31ec5825342eda570acfc9bcb43a44258fceb28/backend/getData.js
8288
*/
8389
function createReactCompositeComponent (vnode) {
90+
const isCompositeComponent = isComposite(vnode)
8491
const _currentElement = createReactElement(vnode)
85-
const node = vnode.component.dom || vnode.dom
92+
const component = isCompositeComponent ? vnode.component : vnode
93+
const node = component.dom
8694

8795
const instance: any = {
8896
// --- ReactDOMComponent properties
8997
getName () {
9098
return typeName(_currentElement)
9199
},
92100
_currentElement: createReactElement(vnode),
93-
props: vnode.props,
94-
state: vnode.state,
95-
forceUpdate: vnode.forceUpdate && vnode.forceUpdate.bind(vnode),
96-
setState: vnode.setState && vnode.setState.bind(vnode),
101+
props: normalizeProps(component.props),
102+
state: component.state,
103+
forceUpdate: component.forceUpdate && component.forceUpdate.bind(component),
104+
setState: component.setState && component.setState.bind(component),
97105

98106
// --- Additional properties used by Nerv devtools
99107
node
@@ -103,16 +111,14 @@ function createReactCompositeComponent (vnode) {
103111
// component tree as `$r` in the console. `_instance` must refer to a
104112
// React Component (or compatible) class instance with `props` and `state`
105113
// fields and `setState()`, `forceUpdate()` methods.
106-
instance._instance = vnode
114+
instance._instance = component
107115

108116
// If the root node returned by this component instance's render function
109117
// was itself a composite component, there will be a `_component` property
110118
// containing the child component instance.
111119
// Otherwise, if the render() function returned an HTML/SVG element,
112120
// create a ReactDOMComponent-like object for the DOM node itself.
113-
instance._renderedComponent = vnode._component
114-
? updateReactComponent(vnode._component)
115-
: updateReactComponent(node)
121+
instance._renderedComponent = updateReactComponent(component._rendered)
116122
return instance
117123
}
118124

@@ -131,17 +137,16 @@ const instanceMap = new Map()
131137
*
132138
* @param {Component|Node} componentOrNode
133139
*/
134-
function updateReactComponent (componentOrNode) {
135-
const newInstance =
136-
componentOrNode instanceof Node
137-
? createReactDOMComponent(componentOrNode)
138-
: createReactCompositeComponent(componentOrNode)
139-
if (instanceMap.has(componentOrNode)) {
140-
const inst = instanceMap.get(componentOrNode)
140+
function updateReactComponent (vnode) {
141+
const newInstance = !isWidget(vnode)
142+
? createReactDOMComponent(vnode)
143+
: createReactCompositeComponent(vnode)
144+
if (instanceMap.has(vnode)) {
145+
const inst = instanceMap.get(vnode)
141146
Object.assign(inst, newInstance)
142147
return inst
143148
}
144-
instanceMap.set(getKeyForVNode(componentOrNode), newInstance)
149+
instanceMap.set(getKeyForVNode(vnode), newInstance)
145150
return newInstance
146151
}
147152

@@ -241,10 +246,9 @@ function createDevToolsBridge () {
241246

242247
/** Notify devtools that a new component instance has been mounted into the DOM. */
243248
const componentAdded = (vnode) => {
244-
const { component, _owner } = vnode
245-
const instance = updateReactComponent(component)
249+
const instance = updateReactComponent(vnode)
246250
// if is root component
247-
if (_owner === null) {
251+
if (vnode.dom) {
248252
instance._rootID = nextRootKey(roots)
249253
roots[instance._rootID] = instance
250254
Mount._renderNewRootComponent(instance)
@@ -267,6 +271,7 @@ function createDevToolsBridge () {
267271
// children
268272
const instance = updateReactComponent(component)
269273
Reconciler.receiveComponent(instance)
274+
console.log(instance)
270275
visitNonCompositeChildren(instance, (childInst) => {
271276
if (!childInst._inDevTools) {
272277
// New DOM child component

0 commit comments

Comments
 (0)