Skip to content

Commit 45f85a6

Browse files
committed
Just ignore events on unmounted components
Fixes #4865 and also seems to fixes #3790.
1 parent 41e4bfb commit 45f85a6

File tree

2 files changed

+75
-6
lines changed

2 files changed

+75
-6
lines changed

src/renderers/dom/client/ReactMount.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -392,12 +392,11 @@ function findFirstReactDOMImpl(node) {
392392
do {
393393
lastID = internalGetID(current);
394394
current = current.parentNode;
395-
invariant(
396-
current != null,
397-
'findFirstReactDOMImpl(...): Unexpected detached subtree found when ' +
398-
'traversing DOM from node `%s`.',
399-
nodeID
400-
);
395+
if (current == null) {
396+
// The passed-in node has been detached from the container it was
397+
// originally rendered into.
398+
return null;
399+
}
401400
} while (lastID !== reactRootID);
402401

403402
if (current === containersByReactRootID[reactRootID]) {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
* @emails react-core
10+
*/
11+
12+
'use strict';
13+
14+
var React;
15+
var ReactDOM;
16+
var ReactTestUtils;
17+
18+
describe('ReactEventIndependence', function() {
19+
beforeEach(function() {
20+
require('mock-modules').dumpCache();
21+
22+
React = require('React');
23+
ReactDOM = require('ReactDOM');
24+
ReactTestUtils = require('ReactTestUtils');
25+
});
26+
27+
it('does not crash with other react inside', function() {
28+
var clicks = 0;
29+
var div = ReactTestUtils.renderIntoDocument(
30+
<div
31+
onClick={() => clicks++}
32+
dangerouslySetInnerHTML={{
33+
__html: '<button data-reactid=".z">click me</div>',
34+
}}
35+
/>
36+
);
37+
ReactTestUtils.SimulateNative.click(div.firstChild);
38+
expect(clicks).toBe(1);
39+
});
40+
41+
it('does not crash with other react outside', function() {
42+
var clicks = 0;
43+
var outer = document.createElement('div');
44+
outer.setAttribute('data-reactid', '.z');
45+
var inner = ReactDOM.render(
46+
<button onClick={() => clicks++}>click me</button>,
47+
outer
48+
);
49+
ReactTestUtils.SimulateNative.click(inner);
50+
expect(clicks).toBe(1);
51+
});
52+
53+
it('does not when event fired on unmounted tree', function() {
54+
var clicks = 0;
55+
var container = document.createElement('div');
56+
var button = ReactDOM.render(
57+
<button onClick={() => clicks++}>click me</button>,
58+
container
59+
);
60+
61+
// Now we unmount the component, as if caused by a non-React event handler
62+
// for the same click we're about to simulate, like closing a layer:
63+
ReactDOM.unmountComponentAtNode(container);
64+
ReactTestUtils.SimulateNative.click(button);
65+
66+
// Since the tree is unmounted, we don't dispatch the click event.
67+
expect(clicks).toBe(0);
68+
});
69+
70+
});

0 commit comments

Comments
 (0)