@samitouri / QOS-React-2 / commits / b80f676d27

Add hooks back for devtools

Ben Alpert committed Nov 3, 2015 at 18:19 UTC b80f676d275d3a88f4d5524731c5398fa04afab6
5 files changed +112 -35
src/renderers/dom/ReactDOM.js
+17
@@ -13,6 +13,7 @@
13
14 'use strict';
15
16 +var ReactDOMComponentTree = require('ReactDOMComponentTree');
17 var ReactDefaultInjection = require('ReactDefaultInjection');
18 var ReactMount = require('ReactMount');
19 var ReactPerf = require('ReactPerf');
@@ -21,6 +22,7 @@ var ReactUpdates = require('ReactUpdates');
22 var ReactVersion = require('ReactVersion');
23
24 var findDOMNode = require('findDOMNode');
25 +var getNativeComponentFromComposite = require('getNativeComponentFromComposite');
26 var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
27 var warning = require('warning');
28
@@ -46,6 +48,21 @@ if (
48 typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
49 typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
50 __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
51 + ComponentTree: {
52 + getClosestInstanceFromNode:
53 + ReactDOMComponentTree.getClosestInstanceFromNode,
54 + getNodeFromInstance: function(inst) {
55 + // inst is an internal instance (but could be a composite)
56 + if (inst._renderedComponent) {
57 + inst = getNativeComponentFromComposite(inst);
58 + }
59 + if (inst) {
60 + return ReactDOMComponentTree.getNodeFromInstance(inst);
61 + } else {
62 + return null;
63 + }
64 + },
65 + },
66 Mount: ReactMount,
67 Reconciler: ReactReconciler,
68 });
src/renderers/dom/client/ReactMount.js
+27 -5
@@ -39,6 +39,8 @@ var ELEMENT_NODE_TYPE = 1;
39 var DOC_NODE_TYPE = 9;
40 var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
41
42 +var instancesByReactRootID = {};
43 +
44 /**
45 * Finds the index of the first character
46 * that's not common between the two given strings.
@@ -181,12 +183,19 @@ function hasNonRootReactChild(container) {
183 );
184 }
185
184 -function getTopLevelWrapperInContainer(container) {
186 +function getNativeRootInstanceInContainer(container) {
187 var rootEl = getReactRootElementInContainer(container);
188 var prevNativeInstance =
189 rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl);
188 - return !prevNativeInstance || prevNativeInstance._nativeParent ? null :
189 - prevNativeInstance._nativeContainerInfo._topLevelWrapper;
190 + return (
191 + prevNativeInstance && !prevNativeInstance._nativeParent ?
192 + prevNativeInstance : null
193 + );
194 +}
195 +
196 +function getTopLevelWrapperInContainer(container) {
197 + var root = getNativeRootInstanceInContainer(container);
198 + return root ? root._nativeContainerInfo._topLevelWrapper : null;
199 }
200
201 /**
@@ -194,7 +203,10 @@ function getTopLevelWrapperInContainer(container) {
203 * composites instead of having to worry about different types of components
204 * here.
205 */
197 -var TopLevelWrapper = function() {};
206 +var topLevelRootCounter = 1;
207 +var TopLevelWrapper = function() {
208 + this.rootID = topLevelRootCounter++;
209 +};
210 TopLevelWrapper.prototype.isReactComponent = {};
211 if (__DEV__) {
212 TopLevelWrapper.displayName = 'TopLevelWrapper';
@@ -226,6 +238,11 @@ var ReactMount = {
238
239 TopLevelWrapper: TopLevelWrapper,
240
241 + /**
242 + * Used by devtools. The keys are not important.
243 + */
244 + _instancesByReactRootID: instancesByReactRootID,
245 +
246 /**
247 * This is a hook provided to support rendering React components while
248 * ensuring that the apparent scroll position of its `container` does not
@@ -261,7 +278,8 @@ var ReactMount = {
278 },
279
280 /**
264 - * Render a new component into the DOM.
281 + * Render a new component into the DOM. Hooked by devtools!
282 + *
283 * @param {ReactElement} nextElement element to render
284 * @param {DOMElement} container container to render into
285 * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
@@ -310,6 +328,9 @@ var ReactMount = {
328 context
329 );
330
331 + var wrapperID = componentInstance._instance.rootID;
332 + instancesByReactRootID[wrapperID] = componentInstance;
333 +
334 return componentInstance;
335 },
336
@@ -526,6 +547,7 @@ var ReactMount = {
547
548 return false;
549 }
550 + delete instancesByReactRootID[prevComponent._instance.rootID];
551 ReactUpdates.batchedUpdates(
552 unmountComponentFromNode,
553 prevComponent,
src/renderers/dom/client/__tests__/ReactMount-test.js
+37 -15
@@ -11,23 +11,33 @@
11
12 'use strict';
13
14 +var React;
15 +var ReactDOM;
16 +var ReactDOMServer;
17 +var ReactMount;
18 +var ReactTestUtils;
19 +var WebComponents;
20 +
21 describe('ReactMount', function() {
15 - var React = require('React');
16 - var ReactDOM = require('ReactDOM');
17 - var ReactDOMServer = require('ReactDOMServer');
18 - var ReactMount = require('ReactMount');
19 - var ReactTestUtils = require('ReactTestUtils');
20 - var WebComponents = WebComponents;
21 -
22 - try {
23 - if (WebComponents === undefined && typeof jest !== 'undefined') {
24 - WebComponents = require('WebComponents');
22 + beforeEach(function() {
23 + jest.resetModuleRegistry();
24 +
25 + React = require('React');
26 + ReactDOM = require('ReactDOM');
27 + ReactDOMServer = require('ReactDOMServer');
28 + ReactMount = require('ReactMount');
29 + ReactTestUtils = require('ReactTestUtils');
30 +
31 + try {
32 + if (WebComponents === undefined && typeof jest !== 'undefined') {
33 + WebComponents = require('WebComponents');
34 + }
35 + } catch (e) {
36 + // Parse error expected on engines that don't support setters
37 + // or otherwise aren't supportable by the polyfill.
38 + // Leave WebComponents undefined.
39 }
26 - } catch (e) {
27 - // Parse error expected on engines that don't support setters
28 - // or otherwise aren't supportable by the polyfill.
29 - // Leave WebComponents undefined.
30 - }
40 + });
41
42 describe('unmountComponentAtNode', function() {
43 it('throws when given a non-node', function() {
@@ -257,4 +267,16 @@ describe('ReactMount', function() {
267
268 expect(calls).toBe(5);
269 });
270 +
271 + it('tracks root instances', function() {
272 + // Used by devtools.
273 + expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(0);
274 + ReactTestUtils.renderIntoDocument(<span />);
275 + expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(1);
276 + var container = document.createElement('div');
277 + ReactDOM.render(<span />, container);
278 + expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(2);
279 + ReactDOM.unmountComponentAtNode(container);
280 + expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(1);
281 + });
282 });
src/renderers/dom/client/findDOMNode.js
+1 -15
@@ -15,25 +15,11 @@
15 var ReactCurrentOwner = require('ReactCurrentOwner');
16 var ReactDOMComponentTree = require('ReactDOMComponentTree');
17 var ReactInstanceMap = require('ReactInstanceMap');
18 -var ReactNodeTypes = require('ReactNodeTypes');
18
19 +var getNativeComponentFromComposite = require('getNativeComponentFromComposite');
20 var invariant = require('invariant');
21 var warning = require('warning');
22
23 -function getNativeComponentFromComposite(inst) {
24 - var type;
25 -
26 - while ((type = inst._renderedNodeType) === ReactNodeTypes.COMPOSITE) {
27 - inst = inst._renderedComponent;
28 - }
29 -
30 - if (type === ReactNodeTypes.NATIVE) {
31 - return inst._renderedComponent;
32 - } else if (type === ReactNodeTypes.EMPTY) {
33 - return null;
34 - }
35 -}
36 -
23 /**
24 * Returns the DOM node rendered by this element.
25 *
src/shared/utils/getNativeComponentFromComposite.js new
+30
@@ -0,0 +1,30 @@
1 +/**
2 + * Copyright 2013-2015, 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 getNativeComponentFromComposite
10 + */
11 +
12 +'use strict';
13 +
14 +var ReactNodeTypes = require('ReactNodeTypes');
15 +
16 +function getNativeComponentFromComposite(inst) {
17 + var type;
18 +
19 + while ((type = inst._renderedNodeType) === ReactNodeTypes.COMPOSITE) {
20 + inst = inst._renderedComponent;
21 + }
22 +
23 + if (type === ReactNodeTypes.NATIVE) {
24 + return inst._renderedComponent;
25 + } else if (type === ReactNodeTypes.EMPTY) {
26 + return null;
27 + }
28 +}
29 +
30 +module.exports = getNativeComponentFromComposite;