From 8df7afc689de7929ed4a5ec4f581b94abb963914 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Tue, 25 Oct 2016 14:37:46 -0700 Subject: [PATCH] Merge React[DOM/Native]TreeTraversal These two implementations are identical. Except for some invariants for some reason. Since this relies on an implementation detail of the internal component tree rather than an implementation detail of the renderer, we might as well merge them and remove the injection. --- src/renderers/dom/shared/ReactDOMInjection.js | 2 - .../dom/shared/ReactDOMTreeTraversal.js | 134 ------------------ src/renderers/native/ReactNativeInjection.js | 2 - .../shared/ReactTreeTraversal.js} | 4 +- .../__tests__/ReactTreeTraversal-test.js} | 30 ++-- .../shared/shared/event/EventPluginUtils.js | 22 +-- .../__tests__/ResponderEventPlugin-test.js | 30 ++-- 7 files changed, 38 insertions(+), 186 deletions(-) delete mode 100644 src/renderers/dom/shared/ReactDOMTreeTraversal.js rename src/renderers/{native/ReactNativeTreeTraversal.js => shared/shared/ReactTreeTraversal.js} (96%) rename src/renderers/{dom/shared/__tests__/ReactDOMTreeTraversal-test.js => shared/shared/__tests__/ReactTreeTraversal-test.js} (91%) diff --git a/src/renderers/dom/shared/ReactDOMInjection.js b/src/renderers/dom/shared/ReactDOMInjection.js index b9058b8602..24ffdae8da 100644 --- a/src/renderers/dom/shared/ReactDOMInjection.js +++ b/src/renderers/dom/shared/ReactDOMInjection.js @@ -22,7 +22,6 @@ var EventPluginUtils = require('EventPluginUtils'); var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactDOMTreeTraversal = require('ReactDOMTreeTraversal'); var ReactEventListener = require('ReactEventListener'); var SVGDOMPropertyConfig = require('SVGDOMPropertyConfig'); var SelectEventPlugin = require('SelectEventPlugin'); @@ -48,7 +47,6 @@ function inject() { */ EventPluginHub.injection.injectEventPluginOrder(DOMEventPluginOrder); EventPluginUtils.injection.injectComponentTree(ReactDOMComponentTree); - EventPluginUtils.injection.injectTreeTraversal(ReactDOMTreeTraversal); /** * Some important event plugins included by default (without having to require diff --git a/src/renderers/dom/shared/ReactDOMTreeTraversal.js b/src/renderers/dom/shared/ReactDOMTreeTraversal.js deleted file mode 100644 index 72cb838035..0000000000 --- a/src/renderers/dom/shared/ReactDOMTreeTraversal.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule ReactDOMTreeTraversal - */ - -'use strict'; - -var invariant = require('invariant'); - -/** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ -function getLowestCommonAncestor(instA, instB) { - invariant('_hostNode' in instA, 'getNodeFromInstance: Invalid argument.'); - invariant('_hostNode' in instB, 'getNodeFromInstance: Invalid argument.'); - - var depthA = 0; - for (var tempA = instA; tempA; tempA = tempA._hostParent) { - depthA++; - } - var depthB = 0; - for (var tempB = instB; tempB; tempB = tempB._hostParent) { - depthB++; - } - - // If A is deeper, crawl up. - while (depthA - depthB > 0) { - instA = instA._hostParent; - depthA--; - } - - // If B is deeper, crawl up. - while (depthB - depthA > 0) { - instB = instB._hostParent; - depthB--; - } - - // Walk in lockstep until we find a match. - var depth = depthA; - while (depth--) { - if (instA === instB) { - return instA; - } - instA = instA._hostParent; - instB = instB._hostParent; - } - return null; -} - -/** - * Return if A is an ancestor of B. - */ -function isAncestor(instA, instB) { - invariant('_hostNode' in instA, 'isAncestor: Invalid argument.'); - invariant('_hostNode' in instB, 'isAncestor: Invalid argument.'); - - while (instB) { - if (instB === instA) { - return true; - } - instB = instB._hostParent; - } - return false; -} - -/** - * Return the parent instance of the passed-in instance. - */ -function getParentInstance(inst) { - invariant('_hostNode' in inst, 'getParentInstance: Invalid argument.'); - - return inst._hostParent; -} - -/** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ -function traverseTwoPhase(inst, fn, arg) { - var path = []; - while (inst) { - path.push(inst); - inst = inst._hostParent; - } - var i; - for (i = path.length; i-- > 0;) { - fn(path[i], 'captured', arg); - } - for (i = 0; i < path.length; i++) { - fn(path[i], 'bubbled', arg); - } -} - -/** - * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that - * should would receive a `mouseEnter` or `mouseLeave` event. - * - * Does not invoke the callback on the nearest common ancestor because nothing - * "entered" or "left" that element. - */ -function traverseEnterLeave(from, to, fn, argFrom, argTo) { - var common = from && to ? getLowestCommonAncestor(from, to) : null; - var pathFrom = []; - while (from && from !== common) { - pathFrom.push(from); - from = from._hostParent; - } - var pathTo = []; - while (to && to !== common) { - pathTo.push(to); - to = to._hostParent; - } - var i; - for (i = 0; i < pathFrom.length; i++) { - fn(pathFrom[i], 'bubbled', argFrom); - } - for (i = pathTo.length; i-- > 0;) { - fn(pathTo[i], 'captured', argTo); - } -} - -module.exports = { - isAncestor: isAncestor, - getLowestCommonAncestor: getLowestCommonAncestor, - getParentInstance: getParentInstance, - traverseTwoPhase: traverseTwoPhase, - traverseEnterLeave: traverseEnterLeave, -}; diff --git a/src/renderers/native/ReactNativeInjection.js b/src/renderers/native/ReactNativeInjection.js index 6f6293fde3..16b8564b58 100644 --- a/src/renderers/native/ReactNativeInjection.js +++ b/src/renderers/native/ReactNativeInjection.js @@ -27,7 +27,6 @@ var ReactNativeComponentTree = require('ReactNativeComponentTree'); var ReactNativeEventEmitter = require('ReactNativeEventEmitter'); var ReactNativeEventPluginOrder = require('ReactNativeEventPluginOrder'); var ReactNativeGlobalResponderHandler = require('ReactNativeGlobalResponderHandler'); -var ReactNativeTreeTraversal = require('ReactNativeTreeTraversal'); var ResponderEventPlugin = require('ResponderEventPlugin'); function inject() { @@ -41,7 +40,6 @@ function inject() { */ EventPluginHub.injection.injectEventPluginOrder(ReactNativeEventPluginOrder); EventPluginUtils.injection.injectComponentTree(ReactNativeComponentTree); - EventPluginUtils.injection.injectTreeTraversal(ReactNativeTreeTraversal); ResponderEventPlugin.injection.injectGlobalResponderHandler( ReactNativeGlobalResponderHandler diff --git a/src/renderers/native/ReactNativeTreeTraversal.js b/src/renderers/shared/shared/ReactTreeTraversal.js similarity index 96% rename from src/renderers/native/ReactNativeTreeTraversal.js rename to src/renderers/shared/shared/ReactTreeTraversal.js index 4e98fa8950..6a2f8b7b8a 100644 --- a/src/renderers/native/ReactNativeTreeTraversal.js +++ b/src/renderers/shared/shared/ReactTreeTraversal.js @@ -6,13 +6,11 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @providesModule ReactNativeTreeTraversal + * @providesModule ReactTreeTraversal */ 'use strict'; -// Same as ReactDOMTreeTraversal without the invariants. - /** * Return the lowest common ancestor of A and B, or null if they are in * different trees. diff --git a/src/renderers/dom/shared/__tests__/ReactDOMTreeTraversal-test.js b/src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js similarity index 91% rename from src/renderers/dom/shared/__tests__/ReactDOMTreeTraversal-test.js rename to src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js index d68855d30c..1164111544 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMTreeTraversal-test.js +++ b/src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js @@ -50,8 +50,8 @@ function renderParentIntoDocument() { return ReactTestUtils.renderIntoDocument(); } -describe('ReactDOMTreeTraversal', () => { - var ReactDOMTreeTraversal; +describe('ReactTreeTraversal', () => { + var ReactTreeTraversal; var aggregatedArgs; function argAggregator(inst, phase, arg) { @@ -67,14 +67,14 @@ describe('ReactDOMTreeTraversal', () => { } beforeEach(() => { - ReactDOMTreeTraversal = require('ReactDOMTreeTraversal'); + ReactTreeTraversal = require('ReactTreeTraversal'); aggregatedArgs = []; }); describe('traverseTwoPhase', () => { it('should not traverse when traversing outside DOM', () => { var expectedAggregation = []; - ReactDOMTreeTraversal.traverseTwoPhase(null, argAggregator, ARG); + ReactTreeTraversal.traverseTwoPhase(null, argAggregator, ARG); expect(aggregatedArgs).toEqual(expectedAggregation); }); @@ -92,7 +92,7 @@ describe('ReactDOMTreeTraversal', () => { {node: parent.refs.P_P1, phase: 'bubbled', arg: ARG}, {node: parent.refs.P, phase: 'bubbled', arg: ARG}, ]; - ReactDOMTreeTraversal.traverseTwoPhase(target, argAggregator, ARG); + ReactTreeTraversal.traverseTwoPhase(target, argAggregator, ARG); expect(aggregatedArgs).toEqual(expectedAggregation); }); @@ -103,7 +103,7 @@ describe('ReactDOMTreeTraversal', () => { {node: parent.refs.P, phase: 'captured', arg: ARG}, {node: parent.refs.P, phase: 'bubbled', arg: ARG}, ]; - ReactDOMTreeTraversal.traverseTwoPhase(target, argAggregator, ARG); + ReactTreeTraversal.traverseTwoPhase(target, argAggregator, ARG); expect(aggregatedArgs).toEqual(expectedAggregation); }); }); @@ -112,7 +112,7 @@ describe('ReactDOMTreeTraversal', () => { it('should not traverse when enter/leaving outside DOM', () => { var target = null; var expectedAggregation = []; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( target, target, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -123,7 +123,7 @@ describe('ReactDOMTreeTraversal', () => { var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1); var enter = getInst(parent.refs.P_P1_C1.refs.DIV_1); var expectedAggregation = []; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -138,7 +138,7 @@ describe('ReactDOMTreeTraversal', () => { // enter/leave shouldn't fire anything on the parent {node: parent.refs.P_P1_C1.refs.DIV_2, phase: 'captured', arg: ARG2}, ]; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -151,7 +151,7 @@ describe('ReactDOMTreeTraversal', () => { var expectedAggregation = [ {node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'bubbled', arg: ARG}, ]; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -166,7 +166,7 @@ describe('ReactDOMTreeTraversal', () => { {node: parent.refs.P_P1, phase: 'captured', arg: ARG2}, {node: parent.refs.P_P1_C1.refs.DIV, phase: 'captured', arg: ARG2}, ]; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -179,7 +179,7 @@ describe('ReactDOMTreeTraversal', () => { var expectedAggregation = [ {node: parent.refs.P, phase: 'captured', arg: ARG2}, ]; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -194,7 +194,7 @@ describe('ReactDOMTreeTraversal', () => { {node: parent.refs.P_P1, phase: 'bubbled', arg: ARG}, {node: parent.refs.P, phase: 'bubbled', arg: ARG}, ]; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -209,7 +209,7 @@ describe('ReactDOMTreeTraversal', () => { {node: parent.refs.P_P1, phase: 'bubbled', arg: ARG}, {node: parent.refs.P, phase: 'bubbled', arg: ARG}, ]; - ReactDOMTreeTraversal.traverseEnterLeave( + ReactTreeTraversal.traverseEnterLeave( leave, enter, argAggregator, ARG, ARG2 ); expect(aggregatedArgs).toEqual(expectedAggregation); @@ -261,7 +261,7 @@ describe('ReactDOMTreeTraversal', () => { var i; for (i = 0; i < ancestors.length; i++) { var plan = ancestors[i]; - var firstCommon = ReactDOMTreeTraversal.getLowestCommonAncestor( + var firstCommon = ReactTreeTraversal.getLowestCommonAncestor( getInst(plan.one), getInst(plan.two) ); diff --git a/src/renderers/shared/shared/event/EventPluginUtils.js b/src/renderers/shared/shared/event/EventPluginUtils.js index 4bad7e316d..c2861ddbf5 100644 --- a/src/renderers/shared/shared/event/EventPluginUtils.js +++ b/src/renderers/shared/shared/event/EventPluginUtils.js @@ -11,6 +11,7 @@ 'use strict'; +var ReactTreeTraversal = require('ReactTreeTraversal'); var ReactErrorUtils = require('ReactErrorUtils'); var invariant = require('invariant'); @@ -25,7 +26,6 @@ var warning = require('warning'); * and actual node references. */ var ComponentTree; -var TreeTraversal; var injection = { injectComponentTree: function(Injected) { ComponentTree = Injected; @@ -39,16 +39,6 @@ var injection = { ); } }, - injectTreeTraversal: function(Injected) { - TreeTraversal = Injected; - if (__DEV__) { - warning( - Injected && Injected.isAncestor && Injected.getLowestCommonAncestor, - 'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' + - 'module is missing isAncestor or getLowestCommonAncestor.' - ); - } - }, }; function isEndish(topLevelType) { @@ -237,19 +227,19 @@ var EventPluginUtils = { return ComponentTree.getNodeFromInstance(node); }, isAncestor: function(a, b) { - return TreeTraversal.isAncestor(a, b); + return ReactTreeTraversal.isAncestor(a, b); }, getLowestCommonAncestor: function(a, b) { - return TreeTraversal.getLowestCommonAncestor(a, b); + return ReactTreeTraversal.getLowestCommonAncestor(a, b); }, getParentInstance: function(inst) { - return TreeTraversal.getParentInstance(inst); + return ReactTreeTraversal.getParentInstance(inst); }, traverseTwoPhase: function(target, fn, arg) { - return TreeTraversal.traverseTwoPhase(target, fn, arg); + return ReactTreeTraversal.traverseTwoPhase(target, fn, arg); }, traverseEnterLeave: function(from, to, fn, argFrom, argTo) { - return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo); + return ReactTreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo); }, injection: injection, diff --git a/src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js b/src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js index 584863a10f..4c95a3e316 100644 --- a/src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js +++ b/src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js @@ -408,20 +408,9 @@ describe('ResponderEventPlugin', () => { beforeEach(() => { jest.resetModuleRegistry(); - EventPluginHub = require('EventPluginHub'); - EventPluginUtils = require('EventPluginUtils'); - ResponderEventPlugin = require('ResponderEventPlugin'); - - EventPluginUtils.injection.injectComponentTree({ - getInstanceFromNode: function(id) { - return idToInstance[id]; - }, - getNodeFromInstance: function(inst) { - return inst._rootNodeID; - }, - }); - - EventPluginUtils.injection.injectTreeTraversal({ + // Inline mock + const ReactTreeTraversal = require('ReactTreeTraversal'); + Object.assign(ReactTreeTraversal, { isAncestor: function(a, b) { return isAncestorIDOf(a._rootNodeID, b._rootNodeID); }, @@ -443,6 +432,19 @@ describe('ResponderEventPlugin', () => { ); }, }); + + EventPluginHub = require('EventPluginHub'); + EventPluginUtils = require('EventPluginUtils'); + ResponderEventPlugin = require('ResponderEventPlugin'); + + EventPluginUtils.injection.injectComponentTree({ + getInstanceFromNode: function(id) { + return idToInstance[id]; + }, + getNodeFromInstance: function(inst) { + return inst._rootNodeID; + }, + }); }); it('should do nothing when no one wants to respond', () => {