Utilize the backtracking during events to figure out if a Fiber was unmounted

We're walking backwards up to the root to find the parent so that we can
propagate events further up to nested React parents. If we don't find a
root, that means that the tree was unmounted and we shouldn't send any
events to it.
This commit is contained in:
Sebastian Markbage
2016-11-22 16:16:47 -08:00
parent a481016883
commit 475a6492c7
3 changed files with 22 additions and 9 deletions
-3
View File
@@ -42,9 +42,6 @@ src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
* can reconcile text arbitrarily split into multiple nodes
* can reconcile text arbitrarily split into multiple nodes on some substitutions only
src/renderers/dom/shared/__tests__/ReactEventIndependence-test.js
* does not when event fired on unmounted tree
src/renderers/dom/shared/__tests__/ReactEventListener-test.js
* should batch between handlers from different roots
+1
View File
@@ -640,6 +640,7 @@ src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
src/renderers/dom/shared/__tests__/ReactEventIndependence-test.js
* does not crash with other react inside
* does not crash with other react outside
* does not when event fired on unmounted tree
src/renderers/dom/shared/__tests__/ReactEventListener-test.js
* should dispatch events from outside React tree
+21 -6
View File
@@ -16,33 +16,38 @@ var ExecutionEnvironment = require('ExecutionEnvironment');
var PooledClass = require('PooledClass');
var ReactDOMComponentTree = require('ReactDOMComponentTree');
var ReactGenericBatching = require('ReactGenericBatching');
var ReactTypeOfWork = require('ReactTypeOfWork');
var getEventTarget = require('getEventTarget');
var getUnboundedScrollPosition = require('getUnboundedScrollPosition');
var { HostContainer } = ReactTypeOfWork;
/**
* Find the deepest React component completely containing the root of the
* passed-in instance (for use when entire React trees are nested within each
* other). If React trees are not nested, returns null.
*/
function findParent(inst) {
function findRootContainerNode(inst) {
// TODO: It may be a good idea to cache this to prevent unnecessary DOM
// traversal, but caching is difficult to do correctly without using a
// mutation observer to listen for all DOM changes.
var container;
if (typeof inst.tag === 'number') {
while (inst.return) {
inst = inst.return;
}
container = inst.stateNode.containerInfo;
if (inst.tag !== HostContainer) {
// This can happen if we're in a detached tree.
return null;
}
return inst.stateNode.containerInfo;
} else {
while (inst._hostParent) {
inst = inst._hostParent;
}
var rootNode = ReactDOMComponentTree.getNodeFromInstance(inst);
container = rootNode.parentNode;
return rootNode.parentNode;
}
return ReactDOMComponentTree.getClosestInstanceFromNode(container);
}
// Used to store ancestor hierarchy in top level callback
@@ -74,8 +79,18 @@ function handleTopLevelImpl(bookKeeping) {
// inconsistencies with ReactMount's node cache. See #1105.
var ancestor = targetInst;
do {
if (!ancestor) {
bookKeeping.ancestors.push(ancestor);
break;
}
var root = findRootContainerNode(ancestor);
if (!root) {
break;
}
bookKeeping.ancestors.push(ancestor);
ancestor = ancestor && findParent(ancestor);
ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(
root
);
} while (ancestor);
for (var i = 0; i < bookKeeping.ancestors.length; i++) {