From 2633a4284f40eb4eecace2f443177233e583a081 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Tue, 25 Oct 2016 14:53:54 -0700 Subject: [PATCH 1/3] Move more files into stack reconciler CallbackQueue and Transaction are specific to the stack reconciler. --- src/renderers/shared/{utils => stack/reconciler}/CallbackQueue.js | 0 src/renderers/shared/{utils => stack/reconciler}/Transaction.js | 0 .../{utils => stack/reconciler}/__tests__/Transaction-test.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/renderers/shared/{utils => stack/reconciler}/CallbackQueue.js (100%) rename src/renderers/shared/{utils => stack/reconciler}/Transaction.js (100%) rename src/renderers/shared/{utils => stack/reconciler}/__tests__/Transaction-test.js (100%) diff --git a/src/renderers/shared/utils/CallbackQueue.js b/src/renderers/shared/stack/reconciler/CallbackQueue.js similarity index 100% rename from src/renderers/shared/utils/CallbackQueue.js rename to src/renderers/shared/stack/reconciler/CallbackQueue.js diff --git a/src/renderers/shared/utils/Transaction.js b/src/renderers/shared/stack/reconciler/Transaction.js similarity index 100% rename from src/renderers/shared/utils/Transaction.js rename to src/renderers/shared/stack/reconciler/Transaction.js diff --git a/src/renderers/shared/utils/__tests__/Transaction-test.js b/src/renderers/shared/stack/reconciler/__tests__/Transaction-test.js similarity index 100% rename from src/renderers/shared/utils/__tests__/Transaction-test.js rename to src/renderers/shared/stack/reconciler/__tests__/Transaction-test.js From 2f8d1689db30a769188f08b79480a1301b736d6f Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 27 Oct 2016 18:54:15 -0700 Subject: [PATCH 2/3] Refactor ResponderEventPlugin to not rely on _rootNodeID Instead of relying on IDs, we now use instances for everything so this should be reflected by the test. This still has a _rootNodeID to store the listeners which I will remove next. --- .../eventPlugins/ResponderEventPlugin.js | 4 +- .../__tests__/ResponderEventPlugin-test.js | 259 ++++++------------ 2 files changed, 85 insertions(+), 178 deletions(-) diff --git a/src/renderers/shared/shared/event/eventPlugins/ResponderEventPlugin.js b/src/renderers/shared/shared/event/eventPlugins/ResponderEventPlugin.js index 2f26f4f24c09..1973592d8a56 100644 --- a/src/renderers/shared/shared/event/eventPlugins/ResponderEventPlugin.js +++ b/src/renderers/shared/shared/event/eventPlugins/ResponderEventPlugin.js @@ -466,8 +466,8 @@ function noResponderTouches(nativeEvent) { var ResponderEventPlugin = { /* For unit testing only */ - _getResponderID: function() { - return responderInst ? responderInst._rootNodeID : null; + _getResponder: function() { + return responderInst; }, eventTypes: eventTypes, 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 4c95a3e31600..557049d31cc2 100644 --- a/src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js +++ b/src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js @@ -80,7 +80,7 @@ var _touchConfig = function( changedTouchObjects ), topLevelType: topType, - targetInst: idToInstance[targetNodeHandle], + targetInst: getInstanceFromNode(targetNodeHandle), }; }; @@ -233,7 +233,7 @@ var registerTestHandlers = function(eventTestConfig, readableIDToID) { } return config.returnVal; }.bind(null, readableID, nodeConfig); - EventPluginHub.putListener(idToInstance[id], registrationName, handler); + EventPluginHub.putListener(getInstanceFromNode(id), registrationName, handler); } }; for (var eventName in eventTestConfig) { @@ -304,146 +304,53 @@ var run = function(config, hierarchyConfig, nativeEventConfig) { ); // +1 for extra ++ }; -var GRANDPARENT_ID = '.0'; -var PARENT_ID = '.0.0'; -var CHILD_ID = '.0.0.0'; -var CHILD_ID2 = '.0.0.1'; +var GRANDPARENT_HOST_NODE = { }; +var PARENT_HOST_NODE = { }; +var CHILD_HOST_NODE = { }; +var CHILD_HOST_NODE2 = { }; -var idToInstance = {}; -[GRANDPARENT_ID, PARENT_ID, CHILD_ID, CHILD_ID2].forEach(function(id) { - idToInstance[id] = {_rootNodeID: id}; -}); +var GRANDPARENT_INST = { _hostParent: null, _rootNodeID: '1', _hostNode: GRANDPARENT_HOST_NODE }; +var PARENT_INST = { _hostParent: GRANDPARENT_INST, _rootNodeID: '2', _hostNode: PARENT_HOST_NODE }; +var CHILD_INST = { _hostParent: PARENT_INST, _rootNodeID: '3', _hostNode: CHILD_HOST_NODE }; +var CHILD_INST2 = { _hostParent: PARENT_INST, _rootNodeID: '4', _hostNode: CHILD_HOST_NODE2 }; + +GRANDPARENT_HOST_NODE._reactInstance = GRANDPARENT_INST; +PARENT_HOST_NODE._reactInstance = PARENT_INST; +CHILD_HOST_NODE._reactInstance = CHILD_INST; +CHILD_HOST_NODE2._reactInstance = CHILD_INST2; var three = { - grandParent: GRANDPARENT_ID, - parent: PARENT_ID, - child: CHILD_ID, + grandParent: GRANDPARENT_HOST_NODE, + parent: PARENT_HOST_NODE, + child: CHILD_HOST_NODE, }; var siblings = { - parent: PARENT_ID, - childOne: CHILD_ID, - childTwo: CHILD_ID2, + parent: PARENT_HOST_NODE, + childOne: CHILD_HOST_NODE, + childTwo: CHILD_HOST_NODE2, }; -describe('ResponderEventPlugin', () => { - - // This test is written against React IDs such as 'root.a.b[10]' but we - // removed those. In order to make those tests still pass with minimum - // surgery, we are inlining the implementation of those IDs here as it - // is the only remaining call site. - - var SEPARATOR = '.'; - - function isBoundary(id, index) { - return id.charAt(index) === SEPARATOR || index === id.length; - } - - function isAncestorIDOf(ancestorID, descendantID) { - return ( - descendantID.indexOf(ancestorID) === 0 && - isBoundary(descendantID, ancestorID.length) - ); - } - - function getParentID(id) { - return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : ''; - } - - function getNextDescendantID(ancestorID, destinationID) { - if (ancestorID === destinationID) { - return ancestorID; - } - // Skip over the ancestor and the immediate separator. Traverse until we hit - // another separator or we reach the end of `destinationID`. - var start = ancestorID.length + SEPARATOR.length; - var i; - for (i = start; i < destinationID.length; i++) { - if (isBoundary(destinationID, i)) { - break; - } - } - return destinationID.substr(0, i); - } - - function getFirstCommonAncestorID(oneID, twoID) { - var minLength = Math.min(oneID.length, twoID.length); - if (minLength === 0) { - return ''; - } - var lastCommonMarkerIndex = 0; - // Use `<=` to traverse until the "EOL" of the shorter string. - for (var i = 0; i <= minLength; i++) { - if (isBoundary(oneID, i) && isBoundary(twoID, i)) { - lastCommonMarkerIndex = i; - } else if (oneID.charAt(i) !== twoID.charAt(i)) { - break; - } - } - return oneID.substr(0, lastCommonMarkerIndex); - } - - function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) { - var traverseUp = isAncestorIDOf(stop, start); - var traverse = traverseUp ? getParentID : getNextDescendantID; - for (var id = start; /* until break */; id = traverse(id, stop)) { - var ret; - if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) { - ret = cb(id, traverseUp ? 'bubbled': 'captured', arg); - } - if (ret === false || id === stop) { - // Only break //after// visiting `stop`. - break; - } - } - } +function getInstanceFromNode(node) { + return node._reactInstance; +} - function traverseTwoPhase(targetID, cb, arg) { - traverseParentPath('', targetID, cb, arg, true, false); - traverseParentPath(targetID, '', cb, arg, false, true); - } +function getNodeFromInstance(inst) { + return inst._hostNode; +} - // -- end of the React ID implementation +describe('ResponderEventPlugin', () => { beforeEach(() => { jest.resetModuleRegistry(); - // Inline mock - const ReactTreeTraversal = require('ReactTreeTraversal'); - Object.assign(ReactTreeTraversal, { - isAncestor: function(a, b) { - return isAncestorIDOf(a._rootNodeID, b._rootNodeID); - }, - getLowestCommonAncestor: function(a, b) { - var commonID = getFirstCommonAncestorID(a._rootNodeID, b._rootNodeID); - return idToInstance[commonID] || null; - }, - getParentInstance: function(inst) { - var id = inst._rootNodeID; - var parentID = id.substr(0, id.lastIndexOf(SEPARATOR)); - return idToInstance[parentID] || null; - }, - traverseTwoPhase: function(target, fn, arg) { - traverseTwoPhase( - target._rootNodeID, - function(id, phase) { - fn(idToInstance[id], phase, arg); - } - ); - }, - }); - EventPluginHub = require('EventPluginHub'); EventPluginUtils = require('EventPluginUtils'); ResponderEventPlugin = require('ResponderEventPlugin'); EventPluginUtils.injection.injectComponentTree({ - getInstanceFromNode: function(id) { - return idToInstance[id]; - }, - getNodeFromInstance: function(inst) { - return inst._rootNodeID; - }, + getInstanceFromNode, + getNodeFromInstance, }); }); @@ -456,12 +363,12 @@ describe('ResponderEventPlugin', () => { config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: false}; config.startShouldSetResponder.bubbled.grandParent = {order: 5, returnVal: false}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); // Now no handlers should be called on `touchEnd`. config = oneEventLoopTestConfig(three); run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); @@ -477,13 +384,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.grandParent = {order: 1}; config.responderStart.grandParent = {order: 2}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.grandParent)); config = oneEventLoopTestConfig(three); config.responderEnd.grandParent = {order: 0}; config.responderRelease.grandParent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder parent while capturing', () => { @@ -493,13 +400,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.parent = {order: 2}; config.responderStart.parent = {order: 3}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); config = oneEventLoopTestConfig(three); config.responderEnd.parent = {order: 0}; config.responderRelease.parent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder child while capturing', () => { @@ -510,13 +417,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.child = {order: 3}; config.responderStart.child = {order: 4}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); config.responderEnd.child = {order: 0}; config.responderRelease.child = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder child while bubbling', () => { @@ -528,13 +435,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.child = {order: 4}; config.responderStart.child = {order: 5}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); config.responderEnd.child = {order: 0}; config.responderRelease.child = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder parent while bubbling', () => { @@ -547,13 +454,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.parent = {order: 5}; config.responderStart.parent = {order: 6}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); config = oneEventLoopTestConfig(three); config.responderEnd.parent = {order: 0}; config.responderRelease.parent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder grandParent while bubbling', () => { @@ -567,13 +474,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.grandParent = {order: 6}; config.responderStart.grandParent = {order: 7}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.grandParent)); config = oneEventLoopTestConfig(three); config.responderEnd.grandParent = {order: 0}; config.responderRelease.grandParent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); @@ -599,13 +506,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.grandParent = {order: 1}; config.responderMove.grandParent = {order: 2}; run(config, three, moveConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.grandParent)); config = oneEventLoopTestConfig(three); config.responderEnd.grandParent = {order: 0}; config.responderRelease.grandParent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder parent while capturing move', () => { @@ -625,13 +532,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.parent = {order: 2}; config.responderMove.parent = {order: 3}; run(config, three, moveConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); config = oneEventLoopTestConfig(three); config.responderEnd.parent = {order: 0}; config.responderRelease.parent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder child while capturing move', () => { @@ -652,13 +559,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.child = {order: 3}; config.responderMove.child = {order: 4}; run(config, three, moveConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); config.responderEnd.child = {order: 0}; config.responderRelease.child = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder child while bubbling move', () => { @@ -680,13 +587,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.child = {order: 4}; config.responderMove.child = {order: 5}; run(config, three, moveConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); config.responderEnd.child = {order: 0}; config.responderRelease.child = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder parent while bubbling move', () => { @@ -709,13 +616,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.parent = {order: 5}; config.responderMove.parent = {order: 6}; run(config, three, moveConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); config = oneEventLoopTestConfig(three); config.responderEnd.parent = {order: 0}; config.responderRelease.parent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should grant responder grandParent while bubbling move', () => { @@ -739,13 +646,13 @@ describe('ResponderEventPlugin', () => { config.responderGrant.grandParent = {order: 6}; config.responderMove.grandParent = {order: 7}; run(config, three, moveConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.grandParent)); config = oneEventLoopTestConfig(three); config.responderEnd.grandParent = {order: 0}; config.responderRelease.grandParent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); @@ -761,7 +668,7 @@ describe('ResponderEventPlugin', () => { config.responderGrant.parent = {order: 2}; config.responderStart.parent = {order: 3}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); // While `parent` is still responder, we create new handlers that verify // the ordering of propagation, restarting the count at `0`. @@ -771,13 +678,13 @@ describe('ResponderEventPlugin', () => { config.startShouldSetResponder.bubbled.grandParent = {order: 1, returnVal: false}; config.responderStart.parent = {order: 2}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); config = oneEventLoopTestConfig(three); config.responderEnd.parent = {order: 0}; config.responderRelease.parent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); it('should bubble negotiation to first common ancestor of responder then transfer', () => { @@ -787,7 +694,7 @@ describe('ResponderEventPlugin', () => { config.responderGrant.parent = {order: 2}; config.responderStart.parent = {order: 3}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); config = oneEventLoopTestConfig(three); @@ -798,19 +705,19 @@ describe('ResponderEventPlugin', () => { config.responderTerminate.parent = {order: 3}; config.responderStart.grandParent = {order: 4}; run(config, three, startConfig(three.child, [three.child, three.child], [1])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.grandParent)); config = oneEventLoopTestConfig(three); config.responderEnd.grandParent = {order: 0}; // one remains\ /one ended \ run(config, three, endConfig(three.child, [three.child, three.child], [1])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.grandParent)); config = oneEventLoopTestConfig(three); config.responderEnd.grandParent = {order: 0}; config.responderRelease.grandParent = {order: 1}; run(config, three, endConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); /** @@ -826,7 +733,7 @@ describe('ResponderEventPlugin', () => { config.startShouldSetResponder.bubbled.grandParent = {order: 3, returnVal: false}; run(config, three, startConfig(three.parent, [three.parent], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); config = oneEventLoopTestConfig(three); @@ -842,7 +749,7 @@ describe('ResponderEventPlugin', () => { config.responderStart.child = {order: 5}; // / Two active touches \ /one of them new\ run(config, three, startConfig(three.child, [three.parent, three.child], [1])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); // Now we remove the original first touch, keeping the second touch that @@ -852,7 +759,7 @@ describe('ResponderEventPlugin', () => { config.responderEnd.child = {order: 0}; // / one ended\ /one remains \ run(config, three, endConfig(three.child, [three.parent, three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); // Okay, now let's add back that first touch (nothing should change) and // then we'll try peeling back the touches in the opposite order to make @@ -868,7 +775,7 @@ describe('ResponderEventPlugin', () => { config.responderStart.child = {order: 4}; // / Two active touches \ /one of them new\ run(config, three, startConfig(three.parent, [three.child, three.parent], [1])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); // Now, move that new touch that had no effect, and did not start within @@ -883,7 +790,7 @@ describe('ResponderEventPlugin', () => { config.responderMove.child = {order: 4}; // / Two active touches \ /one of them moved\ run(config, three, moveConfig(three.parent, [three.child, three.parent], [1])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); @@ -891,7 +798,7 @@ describe('ResponderEventPlugin', () => { config.responderRelease.child = {order: 1}; // /child end \ /parent remain\ run(config, three, endConfig(three.child, [three.child, three.parent], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); @@ -909,7 +816,7 @@ describe('ResponderEventPlugin', () => { config.responderStart.childOne = {order: 4}; run(config, siblings, startConfig(siblings.childOne, [siblings.childOne], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(siblings.childOne)); // If the touch target is the sibling item, the negotiation should only // propagate to first common ancestor of current responder and sibling (so @@ -922,7 +829,7 @@ describe('ResponderEventPlugin', () => { var touchConfig = startConfig(siblings.childTwo, [siblings.childOne, siblings.childTwo], [1]); run(config, siblings, touchConfig); - expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(siblings.childOne)); // move childOne @@ -931,7 +838,7 @@ describe('ResponderEventPlugin', () => { config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false}; config.responderMove.childOne = {order: 2}; run(config, siblings, moveConfig(siblings.childOne, [siblings.childOne, siblings.childTwo], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(siblings.childOne)); // move childTwo: Only negotiates to `parent`. config = oneEventLoopTestConfig(siblings); @@ -939,7 +846,7 @@ describe('ResponderEventPlugin', () => { config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false}; config.responderMove.childOne = {order: 2}; run(config, siblings, moveConfig(siblings.childTwo, [siblings.childOne, siblings.childTwo], [1])); - expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(siblings.childOne)); }); @@ -955,7 +862,7 @@ describe('ResponderEventPlugin', () => { config.responderStart.child = {order: 5}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); // Suppose parent wants to become responder on move, and is rejected config = oneEventLoopTestConfig(three); @@ -971,7 +878,7 @@ describe('ResponderEventPlugin', () => { var touchConfig = moveConfig(three.child, [three.child], [0]); run(config, three, touchConfig); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false}; @@ -986,7 +893,7 @@ describe('ResponderEventPlugin', () => { touchConfig = startConfig(three.child, [three.child, three.child], [1]); run(config, three, touchConfig); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); }); @@ -1002,7 +909,7 @@ describe('ResponderEventPlugin', () => { config.responderStart.child = {order: 5}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); // If the touch target is the sibling item, the negotiation should only // propagate to first common ancestor of current responder and sibling (so @@ -1017,10 +924,10 @@ describe('ResponderEventPlugin', () => { run(config, three, { topLevelType: 'topScroll', - targetInst: idToInstance[three.parent], + targetInst: getInstanceFromNode(three.parent), nativeEvent: {}, }); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); // Now lets let the scroll take control this time. @@ -1034,10 +941,10 @@ describe('ResponderEventPlugin', () => { run(config, three, { topLevelType: 'topScroll', - targetInst: idToInstance[three.parent], + targetInst: getInstanceFromNode(three.parent), nativeEvent: {}, }); - expect(ResponderEventPlugin._getResponderID()).toBe(three.parent); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.parent)); }); @@ -1053,7 +960,7 @@ describe('ResponderEventPlugin', () => { config.responderStart.child = {order: 5}; run(config, three, startConfig(three.child, [three.child], [0])); - expect(ResponderEventPlugin._getResponderID()).toBe(three.child); + expect(ResponderEventPlugin._getResponder()).toBe(getInstanceFromNode(three.child)); config = oneEventLoopTestConfig(three); config.responderEnd.child = {order: 0}; @@ -1066,6 +973,6 @@ describe('ResponderEventPlugin', () => { [0] ); run(config, three, nativeEvent); - expect(ResponderEventPlugin._getResponderID()).toBe(null); + expect(ResponderEventPlugin._getResponder()).toBe(null); }); }); From ea47782aaac8b405c21f0192b7a23b9820e5ace7 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 27 Oct 2016 18:57:30 -0700 Subject: [PATCH 3/3] Create ReactGenericBatching injection wrapper around BatchedUpdates This moves calls that don't know if they're in a Fiber or Stack context to use ReactGenericBatching.batchedUpdates. The corresponding one will be injected from either the stack reconciler and/or the fiber reconciler if they're loaded at the same time. This lets them share the event system when they're both used at once. This can also be useful for libraries that call unstable_batchedUpdates today but don't know which renderer to use. --- .../dom/shared/ReactEventListener.js | 4 +- .../shared/eventPlugins/ChangeEventPlugin.js | 4 +- .../stack/client/ReactDOMStackInjection.js | 5 ++ .../native/ReactNativeEventEmitter.js | 4 +- .../native/ReactNativeStackInjection.js | 5 ++ .../shared/event/ReactGenericBatching.js | 53 +++++++++++++++++++ 6 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 src/renderers/shared/shared/event/ReactGenericBatching.js diff --git a/src/renderers/dom/shared/ReactEventListener.js b/src/renderers/dom/shared/ReactEventListener.js index 8a329e9599c6..950cbe22630d 100644 --- a/src/renderers/dom/shared/ReactEventListener.js +++ b/src/renderers/dom/shared/ReactEventListener.js @@ -15,7 +15,7 @@ var EventListener = require('EventListener'); var ExecutionEnvironment = require('ExecutionEnvironment'); var PooledClass = require('PooledClass'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactUpdates = require('ReactUpdates'); +var ReactGenericBatching = require('ReactGenericBatching'); var getEventTarget = require('getEventTarget'); var getUnboundedScrollPosition = require('getUnboundedScrollPosition'); @@ -165,7 +165,7 @@ var ReactEventListener = { try { // Event queue being processed in the same cycle allows // `preventDefault`. - ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping); + ReactGenericBatching.batchedUpdates(handleTopLevelImpl, bookKeeping); } finally { TopLevelCallbackBookKeeping.release(bookKeeping); } diff --git a/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js b/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js index db8a78aa704d..06d153f077af 100644 --- a/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js +++ b/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js @@ -15,7 +15,7 @@ var EventPluginHub = require('EventPluginHub'); var EventPropagators = require('EventPropagators'); var ExecutionEnvironment = require('ExecutionEnvironment'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactUpdates = require('ReactUpdates'); +var ReactGenericBatching = require('ReactGenericBatching'); var SyntheticEvent = require('SyntheticEvent'); var inputValueTracking = require('inputValueTracking'); @@ -98,7 +98,7 @@ function manualDispatchChangeEvent(nativeEvent) { // components don't work properly in conjunction with event bubbling because // the component is rerendered and the value reverted before all the event // handlers can run. See https://github.com/facebook/react/issues/708. - ReactUpdates.batchedUpdates(runEventInBatch, event); + ReactGenericBatching.batchedUpdates(runEventInBatch, event); } function runEventInBatch(event) { diff --git a/src/renderers/dom/stack/client/ReactDOMStackInjection.js b/src/renderers/dom/stack/client/ReactDOMStackInjection.js index 7da0618673cf..6bf56262ac9d 100644 --- a/src/renderers/dom/stack/client/ReactDOMStackInjection.js +++ b/src/renderers/dom/stack/client/ReactDOMStackInjection.js @@ -19,6 +19,7 @@ var ReactDOMEmptyComponent = require('ReactDOMEmptyComponent'); var ReactDOMTextComponent = require('ReactDOMTextComponent'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); var ReactEmptyComponent = require('ReactEmptyComponent'); +var ReactGenericBatching = require('ReactGenericBatching'); var ReactHostComponent = require('ReactHostComponent'); var ReactReconcileTransaction = require('ReactReconcileTransaction'); var ReactUpdates = require('ReactUpdates'); @@ -34,6 +35,10 @@ function inject() { } alreadyInjected = true; + ReactGenericBatching.injection.injectStackBatchedUpdates( + ReactUpdates.batchedUpdates + ); + ReactHostComponent.injection.injectGenericComponentClass( ReactDOMComponent ); diff --git a/src/renderers/native/ReactNativeEventEmitter.js b/src/renderers/native/ReactNativeEventEmitter.js index 0c4c3a7da1d3..c476bc166f37 100644 --- a/src/renderers/native/ReactNativeEventEmitter.js +++ b/src/renderers/native/ReactNativeEventEmitter.js @@ -16,7 +16,7 @@ var EventPluginRegistry = require('EventPluginRegistry'); var ReactEventEmitterMixin = require('ReactEventEmitterMixin'); var ReactNativeComponentTree = require('ReactNativeComponentTree'); var ReactNativeTagHandles = require('ReactNativeTagHandles'); -var ReactUpdates = require('ReactUpdates'); +var ReactGenericBatching = require('ReactGenericBatching'); var warning = require('warning'); @@ -123,7 +123,7 @@ var ReactNativeEventEmitter = { // any events. return; } - ReactUpdates.batchedUpdates(function() { + ReactGenericBatching.batchedUpdates(function() { ReactNativeEventEmitter.handleTopLevel( topLevelType, inst, diff --git a/src/renderers/native/ReactNativeStackInjection.js b/src/renderers/native/ReactNativeStackInjection.js index 01181a65f81d..83a5bcd4d4b6 100644 --- a/src/renderers/native/ReactNativeStackInjection.js +++ b/src/renderers/native/ReactNativeStackInjection.js @@ -23,6 +23,7 @@ var React = require('React'); var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); var ReactEmptyComponent = require('ReactEmptyComponent'); +var ReactGenericBatching = require('ReactGenericBatching'); var ReactHostComponent = require('ReactHostComponent'); var ReactNativeComponentEnvironment = require('ReactNativeComponentEnvironment'); var ReactNativeTextComponent = require('ReactNativeTextComponent'); @@ -32,6 +33,10 @@ var ReactUpdates = require('ReactUpdates'); var invariant = require('invariant'); function inject() { + ReactGenericBatching.injection.injectStackBatchedUpdates( + ReactUpdates.batchedUpdates + ); + ReactUpdates.injection.injectReconcileTransaction( ReactNativeComponentEnvironment.ReactReconcileTransaction ); diff --git a/src/renderers/shared/shared/event/ReactGenericBatching.js b/src/renderers/shared/shared/event/ReactGenericBatching.js new file mode 100644 index 000000000000..6461ae973dbb --- /dev/null +++ b/src/renderers/shared/shared/event/ReactGenericBatching.js @@ -0,0 +1,53 @@ +/** + * Copyright 2013-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 ReactGenericBatching + */ + +'use strict'; + +// Used as a way to call batchedUpdates when we don't know if we're in a Fiber +// or Stack context. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var stackBatchedUpdates = function(fn, a, b, c, d, e) { + fn(a, b, c, d, e); +}; +var fiberPerformSynchronousWork = function(fn, bookkeeping) { + fn(bookkeeping); +}; + +function performFiberBatchedUpdates(fn, bookkeeping) { + // If we have Fiber loaded, we need to wrap this in a batching call so that + // Fiber can apply its default priority for this call. + fiberPerformSynchronousWork(fn, bookkeeping); +} +function batchedUpdates(fn, bookkeeping) { + // We first perform work with the stack batching strategy, by passing our + // indirection to it. + stackBatchedUpdates(performFiberBatchedUpdates, fn, bookkeeping); +} + +var ReactGenericBatchingInjection = { + injectStackBatchedUpdates: function(_batchedUpdates) { + stackBatchedUpdates = _batchedUpdates; + }, + injectFiberPerformSynchronousWork: function(_performSynchronousWork) { + fiberPerformSynchronousWork = _performSynchronousWork; + }, +}; + +var ReactGenericBatching = { + batchedUpdates, + injection: ReactGenericBatchingInjection, +}; + +module.exports = ReactGenericBatching;