Implement findDOMNode for Fiber
This is the naive implementation that doesn't cover the case where there are two diverging fibers, or if this tree is unmounted.
Sebastian Markbage committed
Oct 22, 2016 at 17:41 UTC
298d0c3e05e618b7c46b7da0a4e214a20ead3670
3 files changed
+83
-4
src/renderers/dom/fiber/ReactDOMFiber.js
+12
@@ -146,6 +146,18 @@ var ReactDOM = {
146
}
147
},
148
149
+ findDOMNode(componentOrElement : Element | ?ReactComponent<any, any, any>) : null | Element | Text {
150
+ if (componentOrElement == null) {
151
+ return null;
152
+ }
153
+ // Unsound duck typing.
154
+ const component = (componentOrElement : any);
155
+ if (component.nodeType === 1) {
156
+ return component;
157
+ }
158
+ return DOMRenderer.findHostInstance(component);
159
+ },
160
+
161
};
162
163
module.exports = ReactDOM;
src/renderers/shared/fiber/ReactFiberReconciler.js
+17
-4
@@ -24,6 +24,8 @@ if (__DEV__) {
24
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
25
}
26
27
+var { findCurrentHostFiber } = require('ReactFiberTreeReflection');
28
+
29
type Deadline = {
30
timeRemaining : () => number
31
};
@@ -58,17 +60,20 @@ export type HostConfig<T, P, I, TI, C> = {
60
61
type OpaqueNode = Fiber;
62
61
-export type Reconciler<C, I> = {
63
+export type Reconciler<C, I, TI> = {
64
mountContainer(element : ReactElement<any>, containerInfo : C) : OpaqueNode,
65
updateContainer(element : ReactElement<any>, container : OpaqueNode) : void,
66
unmountContainer(container : OpaqueNode) : void,
67
performWithPriority(priorityLevel : PriorityLevel, fn : Function) : void,
68
69
// Used to extract the return value from the initial render. Legacy API.
68
- getPublicRootInstance(container : OpaqueNode) : (ReactComponent<any, any, any> | I | null),
70
+ getPublicRootInstance(container : OpaqueNode) : (ReactComponent<any, any, any> | TI | I | null),
71
+
72
+ // Use for findDOMNode/findHostNode. Legacy API.
73
+ findHostInstance(component : ReactComponent<any, any, any>) : I | TI | null,
74
};
75
71
-module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) : Reconciler<C, I> {
76
+module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) : Reconciler<C, I, TI> {
77
78
var { scheduleWork, performWithPriority } = ReactFiberScheduler(config);
79
@@ -122,7 +127,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) :
127
128
performWithPriority,
129
125
- getPublicRootInstance(container : OpaqueNode) : (ReactComponent<any, any, any> | I | null) {
130
+ getPublicRootInstance(container : OpaqueNode) : (ReactComponent<any, any, any> | I | TI | null) {
131
const root : FiberRoot = (container.stateNode : any);
132
const containerFiber = root.current;
133
if (!containerFiber.child) {
@@ -131,6 +136,14 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) :
136
return containerFiber.child.stateNode;
137
},
138
139
+ findHostInstance(component : ReactComponent<any, any, any>) : I | TI | null {
140
+ const fiber = findCurrentHostFiber(component);
141
+ if (!fiber) {
142
+ return null;
143
+ }
144
+ return fiber.stateNode;
145
+ },
146
+
147
};
148
149
};
src/renderers/shared/fiber/ReactFiberTreeReflection.js
new
+54
@@ -0,0 +1,54 @@
1
+/**
2
+ * Copyright 2013-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactFiberTreeReflection
10
+ * @flow
11
+ */
12
+
13
+'use strict';
14
+
15
+import type { Fiber } from 'ReactFiber';
16
+
17
+var ReactInstanceMap = require('ReactInstanceMap');
18
+
19
+var {
20
+ ClassComponent,
21
+ HostContainer,
22
+ HostComponent,
23
+ HostText,
24
+} = require('ReactTypeOfWork');
25
+
26
+exports.findCurrentHostFiber = function(component : ReactComponent<any, any, any>) : Fiber | null {
27
+ var parent : ?Fiber = ReactInstanceMap.get(component);
28
+ if (!parent) {
29
+ return null;
30
+ }
31
+
32
+ // TODO: This search is incomplete because this could be one of two possible fibers.
33
+ let node : Fiber = parent;
34
+ while (true) {
35
+ if (node.tag === HostComponent || node.tag === HostText) {
36
+ return node;
37
+ } else if (node.child) {
38
+ // TODO: Coroutines need to visit the stateNode.
39
+ node = node.child;
40
+ continue;
41
+ }
42
+ if (node === parent) {
43
+ return null;
44
+ }
45
+ while (!node.sibling) {
46
+ if (!node.return || node.return === parent) {
47
+ return null;
48
+ }
49
+ node = node.return;
50
+ }
51
+ node = node.sibling;
52
+ }
53
+ return null;
54
+};