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.
Sebastian Markbage committed
Nov 20, 2016 at 23:41 UTC
475a6492c78b325da97d2b7b806e9945199eb92e
3 files changed
+22
-9
scripts/fiber/tests-failing.txt
-3
@@ -42,9 +42,6 @@ src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
42
* can reconcile text arbitrarily split into multiple nodes
43
* can reconcile text arbitrarily split into multiple nodes on some substitutions only
44
45
-src/renderers/dom/shared/__tests__/ReactEventIndependence-test.js
46
-* does not when event fired on unmounted tree
47
-
45
src/renderers/dom/shared/__tests__/ReactEventListener-test.js
46
* should batch between handlers from different roots
47
scripts/fiber/tests-passing.txt
+1
@@ -640,6 +640,7 @@ src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
640
src/renderers/dom/shared/__tests__/ReactEventIndependence-test.js
641
* does not crash with other react inside
642
* does not crash with other react outside
643
+* does not when event fired on unmounted tree
644
645
src/renderers/dom/shared/__tests__/ReactEventListener-test.js
646
* should dispatch events from outside React tree
src/renderers/dom/shared/ReactEventListener.js
+21
-6
@@ -16,33 +16,38 @@ var ExecutionEnvironment = require('ExecutionEnvironment');
16
var PooledClass = require('PooledClass');
17
var ReactDOMComponentTree = require('ReactDOMComponentTree');
18
var ReactGenericBatching = require('ReactGenericBatching');
19
+var ReactTypeOfWork = require('ReactTypeOfWork');
20
21
var getEventTarget = require('getEventTarget');
22
var getUnboundedScrollPosition = require('getUnboundedScrollPosition');
23
24
+var { HostContainer } = ReactTypeOfWork;
25
+
26
/**
27
* Find the deepest React component completely containing the root of the
28
* passed-in instance (for use when entire React trees are nested within each
29
* other). If React trees are not nested, returns null.
30
*/
28
-function findParent(inst) {
31
+function findRootContainerNode(inst) {
32
// TODO: It may be a good idea to cache this to prevent unnecessary DOM
33
// traversal, but caching is difficult to do correctly without using a
34
// mutation observer to listen for all DOM changes.
32
- var container;
35
if (typeof inst.tag === 'number') {
36
while (inst.return) {
37
inst = inst.return;
38
}
37
- container = inst.stateNode.containerInfo;
39
+ if (inst.tag !== HostContainer) {
40
+ // This can happen if we're in a detached tree.
41
+ return null;
42
+ }
43
+ return inst.stateNode.containerInfo;
44
} else {
45
while (inst._hostParent) {
46
inst = inst._hostParent;
47
}
48
var rootNode = ReactDOMComponentTree.getNodeFromInstance(inst);
43
- container = rootNode.parentNode;
49
+ return rootNode.parentNode;
50
}
45
- return ReactDOMComponentTree.getClosestInstanceFromNode(container);
51
}
52
53
// Used to store ancestor hierarchy in top level callback
@@ -74,8 +79,18 @@ function handleTopLevelImpl(bookKeeping) {
79
// inconsistencies with ReactMount's node cache. See #1105.
80
var ancestor = targetInst;
81
do {
82
+ if (!ancestor) {
83
+ bookKeeping.ancestors.push(ancestor);
84
+ break;
85
+ }
86
+ var root = findRootContainerNode(ancestor);
87
+ if (!root) {
88
+ break;
89
+ }
90
bookKeeping.ancestors.push(ancestor);
78
- ancestor = ancestor && findParent(ancestor);
91
+ ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(
92
+ root
93
+ );
94
} while (ancestor);
95
96
for (var i = 0; i < bookKeeping.ancestors.length; i++) {