@samitouri / QOS-React-2 / commits / 298d0c3e05

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 +};