mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix development mode hang when iframe is removed (#19220)
* Fix development mode hang when iframe is removed * Also fix #16734
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
import invariant from 'shared/invariant';
|
||||
|
||||
let invokeGuardedCallbackImpl = function<A, B, C, D, E, F, Context>(
|
||||
function invokeGuardedCallbackProd<A, B, C, D, E, F, Context>(
|
||||
name: string | null,
|
||||
func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
|
||||
context: Context,
|
||||
@@ -26,7 +26,9 @@ let invokeGuardedCallbackImpl = function<A, B, C, D, E, F, Context>(
|
||||
} catch (error) {
|
||||
this.onError(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
|
||||
|
||||
if (__DEV__) {
|
||||
// In DEV mode, we swap out invokeGuardedCallback for a special version
|
||||
@@ -58,7 +60,15 @@ if (__DEV__) {
|
||||
) {
|
||||
const fakeNode = document.createElement('react');
|
||||
|
||||
const invokeGuardedCallbackDev = function<A, B, C, D, E, F, Context>(
|
||||
invokeGuardedCallbackImpl = function invokeGuardedCallbackDev<
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
Context,
|
||||
>(
|
||||
name: string | null,
|
||||
func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
|
||||
context: Context,
|
||||
@@ -85,6 +95,7 @@ if (__DEV__) {
|
||||
);
|
||||
const evt = document.createEvent('Event');
|
||||
|
||||
let didCall = false;
|
||||
// Keeps track of whether the user-provided callback threw an error. We
|
||||
// set this to true at the beginning, then set it to false right after
|
||||
// calling the function. If the function errors, `didError` will never be
|
||||
@@ -105,11 +116,7 @@ if (__DEV__) {
|
||||
'event',
|
||||
);
|
||||
|
||||
// Create an event handler for our fake event. We will synchronously
|
||||
// dispatch our fake event using `dispatchEvent`. Inside the handler, we
|
||||
// call the user-provided callback.
|
||||
const funcArgs = Array.prototype.slice.call(arguments, 3);
|
||||
function callCallback() {
|
||||
function restoreAfterDispatch() {
|
||||
// We immediately remove the callback from event listeners so that
|
||||
// nested `invokeGuardedCallback` calls do not clash. Otherwise, a
|
||||
// nested call would trigger the fake event handlers of any call higher
|
||||
@@ -126,7 +133,15 @@ if (__DEV__) {
|
||||
) {
|
||||
window.event = windowEvent;
|
||||
}
|
||||
}
|
||||
|
||||
// Create an event handler for our fake event. We will synchronously
|
||||
// dispatch our fake event using `dispatchEvent`. Inside the handler, we
|
||||
// call the user-provided callback.
|
||||
const funcArgs = Array.prototype.slice.call(arguments, 3);
|
||||
function callCallback() {
|
||||
didCall = true;
|
||||
restoreAfterDispatch();
|
||||
func.apply(context, funcArgs);
|
||||
didError = false;
|
||||
}
|
||||
@@ -183,7 +198,7 @@ if (__DEV__) {
|
||||
Object.defineProperty(window, 'event', windowEventDescriptor);
|
||||
}
|
||||
|
||||
if (didError) {
|
||||
if (didCall && didError) {
|
||||
if (!didSetError) {
|
||||
// The callback errored, but the error event never fired.
|
||||
error = new Error(
|
||||
@@ -208,9 +223,16 @@ if (__DEV__) {
|
||||
|
||||
// Remove our event listeners
|
||||
window.removeEventListener('error', handleWindowError);
|
||||
};
|
||||
|
||||
invokeGuardedCallbackImpl = invokeGuardedCallbackDev;
|
||||
if (!didCall) {
|
||||
// Something went really wrong, and our event was not dispatched.
|
||||
// https://github.com/facebook/react/issues/16734
|
||||
// https://github.com/facebook/react/issues/16585
|
||||
// Fall back to the production implementation.
|
||||
restoreAfterDispatch();
|
||||
return invokeGuardedCallbackProd.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user