@samitouri / QOS-React-2 / commits / 45f85a6cc5

Just ignore events on unmounted components

Fixes #4865 and also seems to fixes #3790.

Ben Alpert committed Sep 17, 2015 at 17:27 UTC 45f85a6cc5707cd798aba350ae4f6dbe99ede6dc
2 files changed +75 -6
src/renderers/dom/client/ReactMount.js
+5 -6
@@ -392,12 +392,11 @@ function findFirstReactDOMImpl(node) {
392 do {
393 lastID = internalGetID(current);
394 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 + }
400 } while (lastID !== reactRootID);
401
402 if (current === containersByReactRootID[reactRootID]) {
src/renderers/dom/client/__tests__/ReactEventIndependence-test.js new
+70
@@ -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 +});