9
9
10
10
import invariant from 'shared/invariant' ;
11
11
12
- let invokeGuardedCallbackImpl = function < A , B , C , D , E , F , Context > (
12
+ function invokeGuardedCallbackProd < A , B , C , D , E , F , Context > (
13
13
name : string | null ,
14
14
func : ( a : A , b : B , c : C , d : D , e : E , f : F ) = > mixed ,
15
15
context : Context ,
@@ -26,7 +26,9 @@ let invokeGuardedCallbackImpl = function<A, B, C, D, E, F, Context>(
26
26
} catch ( error ) {
27
27
this . onError ( error ) ;
28
28
}
29
- } ;
29
+ }
30
+
31
+ let invokeGuardedCallbackImpl = invokeGuardedCallbackProd ;
30
32
31
33
if ( __DEV__ ) {
32
34
// In DEV mode, we swap out invokeGuardedCallback for a special version
@@ -58,7 +60,15 @@ if (__DEV__) {
58
60
) {
59
61
const fakeNode = document . createElement ( 'react' ) ;
60
62
61
- const invokeGuardedCallbackDev = function < A , B , C , D , E , F , Context > (
63
+ invokeGuardedCallbackImpl = function invokeGuardedCallbackDev <
64
+ A ,
65
+ B ,
66
+ C ,
67
+ D ,
68
+ E ,
69
+ F ,
70
+ Context ,
71
+ > (
62
72
name : string | null ,
63
73
func : ( a : A , b : B , c : C , d : D , e : E , f : F ) = > mixed ,
64
74
context : Context ,
@@ -85,6 +95,7 @@ if (__DEV__) {
85
95
) ;
86
96
const evt = document . createEvent ( 'Event' ) ;
87
97
98
+ let didCall = false ;
88
99
// Keeps track of whether the user-provided callback threw an error. We
89
100
// set this to true at the beginning, then set it to false right after
90
101
// calling the function. If the function errors, `didError` will never be
@@ -105,11 +116,7 @@ if (__DEV__) {
105
116
'event' ,
106
117
) ;
107
118
108
- // Create an event handler for our fake event. We will synchronously
109
- // dispatch our fake event using `dispatchEvent`. Inside the handler, we
110
- // call the user-provided callback.
111
- const funcArgs = Array . prototype . slice . call ( arguments , 3 ) ;
112
- function callCallback ( ) {
119
+ function restoreAfterDispatch ( ) {
113
120
// We immediately remove the callback from event listeners so that
114
121
// nested `invokeGuardedCallback` calls do not clash. Otherwise, a
115
122
// nested call would trigger the fake event handlers of any call higher
@@ -126,7 +133,15 @@ if (__DEV__) {
126
133
) {
127
134
window . event = windowEvent ;
128
135
}
136
+ }
129
137
138
+ // Create an event handler for our fake event. We will synchronously
139
+ // dispatch our fake event using `dispatchEvent`. Inside the handler, we
140
+ // call the user-provided callback.
141
+ const funcArgs = Array . prototype . slice . call ( arguments , 3 ) ;
142
+ function callCallback ( ) {
143
+ didCall = true ;
144
+ restoreAfterDispatch ( ) ;
130
145
func . apply ( context , funcArgs ) ;
131
146
didError = false ;
132
147
}
@@ -183,7 +198,7 @@ if (__DEV__) {
183
198
Object . defineProperty ( window , 'event' , windowEventDescriptor ) ;
184
199
}
185
200
186
- if ( didError ) {
201
+ if ( didCall && didError ) {
187
202
if ( ! didSetError ) {
188
203
// The callback errored, but the error event never fired.
189
204
error = new Error (
@@ -208,9 +223,16 @@ if (__DEV__) {
208
223
209
224
// Remove our event listeners
210
225
window . removeEventListener ( 'error' , handleWindowError ) ;
211
- } ;
212
226
213
- invokeGuardedCallbackImpl = invokeGuardedCallbackDev ;
227
+ if ( ! didCall ) {
228
+ // Something went really wrong, and our event was not dispatched.
229
+ // https://github.com/facebook/react/issues/16734
230
+ // https://github.com/facebook/react/issues/16585
231
+ // Fall back to the production implementation.
232
+ restoreAfterDispatch ( ) ;
233
+ return invokeGuardedCallbackProd . apply ( this , arguments ) ;
234
+ }
235
+ } ;
214
236
}
215
237
}
216
238
0 commit comments