@@ -20,7 +20,6 @@ import type {
20
20
import type { ReactNodeList } from 'shared/ReactTypes' ;
21
21
22
22
import { REACT_MEMO_TYPE , REACT_FORWARD_REF_TYPE } from 'shared/ReactSymbols' ;
23
- import warningWithoutStack from 'shared/warningWithoutStack' ;
24
23
25
24
type Signature = { |
26
25
ownKey : string ,
@@ -29,6 +28,13 @@ type Signature = {|
29
28
getCustomHooks : ( ) => Array < Function > ,
30
29
| } ;
31
30
31
+ type RendererHelpers = { |
32
+ findHostInstancesForRefresh : FindHostInstancesForRefresh ,
33
+ scheduleRefresh : ScheduleRefresh ,
34
+ scheduleRoot : ScheduleRoot ,
35
+ setRefreshHandler : SetRefreshHandler ,
36
+ | } ;
37
+
32
38
if ( ! __DEV__ ) {
33
39
throw new Error (
34
40
'React Refresh runtime should not be included in the production bundle.' ,
@@ -56,10 +62,9 @@ WeakMap<any, Family> | Map<any, Family> = new PossiblyWeakMap();
56
62
let pendingUpdates : Array < [ Family , any ] > = [ ] ;
57
63
58
64
// This is injected by the renderer via DevTools global hook.
59
- let setRefreshHandler : null | SetRefreshHandler = null ;
60
- let scheduleRefresh : null | ScheduleRefresh = null ;
61
- let scheduleRoot : null | ScheduleRoot = null ;
62
- let findHostInstancesForRefresh : null | FindHostInstancesForRefresh = null ;
65
+ let helpersByRendererID : Map < number , RendererHelpers > = new Map ( ) ;
66
+
67
+ let helpersByRoot : Map < FiberRoot , RendererHelpers > = new Map ( ) ;
63
68
64
69
// We keep track of mounted roots so we can schedule updates.
65
70
let mountedRoots : Set < FiberRoot > = new Set ( ) ;
@@ -182,49 +187,23 @@ export function performReactRefresh(): RefreshUpdate | null {
182
187
staleFamilies, // Families that will be remounted
183
188
} ;
184
189
185
- if ( typeof setRefreshHandler !== 'function' ) {
186
- warningWithoutStack (
187
- false ,
188
- 'Could not find the setRefreshHandler() implementation. ' +
189
- 'This likely means that injectIntoGlobalHook() was either ' +
190
- 'called before the global DevTools hook was set up, or after the ' +
191
- 'renderer has already initialized. Please file an issue with a reproducing case.' ,
192
- ) ;
193
- return null ;
194
- }
195
-
196
- if ( typeof scheduleRefresh !== 'function' ) {
197
- warningWithoutStack (
198
- false ,
199
- 'Could not find the scheduleRefresh() implementation. ' +
200
- 'This likely means that injectIntoGlobalHook() was either ' +
201
- 'called before the global DevTools hook was set up, or after the ' +
202
- 'renderer has already initialized. Please file an issue with a reproducing case.' ,
203
- ) ;
204
- return null ;
205
- }
206
- if ( typeof scheduleRoot !== 'function' ) {
207
- warningWithoutStack (
208
- false ,
209
- 'Could not find the scheduleRoot() implementation. ' +
210
- 'This likely means that injectIntoGlobalHook() was either ' +
211
- 'called before the global DevTools hook was set up, or after the ' +
212
- 'renderer has already initialized. Please file an issue with a reproducing case.' ,
213
- ) ;
214
- return null ;
215
- }
216
- const scheduleRefreshForRoot = scheduleRefresh ;
217
- const scheduleRenderForRoot = scheduleRoot ;
218
-
219
- // Even if there are no roots, set the handler on first update.
220
- // This ensures that if *new* roots are mounted, they'll use the resolve handler.
221
- setRefreshHandler ( resolveFamily ) ;
190
+ helpersByRendererID . forEach ( helpers => {
191
+ // Even if there are no roots, set the handler on first update.
192
+ // This ensures that if *new* roots are mounted, they'll use the resolve handler.
193
+ helpers . setRefreshHandler ( resolveFamily ) ;
194
+ } ) ;
222
195
223
196
let didError = false ;
224
197
let firstError = null ;
225
198
failedRoots . forEach ( ( element , root ) => {
199
+ const helpers = helpersByRoot . get ( root ) ;
200
+ if ( helpers === undefined ) {
201
+ throw new Error (
202
+ 'Could not find helpers for a root. This is a bug in React Refresh.' ,
203
+ ) ;
204
+ }
226
205
try {
227
- scheduleRenderForRoot ( root , element ) ;
206
+ helpers . scheduleRoot ( root , element ) ;
228
207
} catch ( err ) {
229
208
if ( ! didError ) {
230
209
didError = true ;
@@ -234,8 +213,14 @@ export function performReactRefresh(): RefreshUpdate | null {
234
213
}
235
214
} ) ;
236
215
mountedRoots . forEach ( root => {
216
+ const helpers = helpersByRoot . get ( root ) ;
217
+ if ( helpers === undefined ) {
218
+ throw new Error (
219
+ 'Could not find helpers for a root. This is a bug in React Refresh.' ,
220
+ ) ;
221
+ }
237
222
try {
238
- scheduleRefreshForRoot ( root , update ) ;
223
+ helpers . scheduleRefresh ( root , update ) ;
239
224
} catch ( err ) {
240
225
if ( ! didError ) {
241
226
didError = true ;
@@ -359,20 +344,18 @@ export function findAffectedHostInstances(
359
344
families : Array < Family > ,
360
345
) : Set < Instance > {
361
346
if ( __DEV__ ) {
362
- if ( typeof findHostInstancesForRefresh !== 'function' ) {
363
- warningWithoutStack (
364
- false ,
365
- 'Could not find the findHostInstancesForRefresh() implementation. ' +
366
- 'This likely means that injectIntoGlobalHook() was either ' +
367
- 'called before the global DevTools hook was set up, or after the ' +
368
- 'renderer has already initialized. Please file an issue with a reproducing case.' ,
369
- ) ;
370
- return new Set ( ) ;
371
- }
372
- const findInstances = findHostInstancesForRefresh ;
373
347
let affectedInstances = new Set ( ) ;
374
348
mountedRoots . forEach ( root => {
375
- const instancesForRoot = findInstances ( root , families ) ;
349
+ const helpers = helpersByRoot . get ( root ) ;
350
+ if ( helpers === undefined ) {
351
+ throw new Error (
352
+ 'Could not find helpers for a root. This is a bug in React Refresh.' ,
353
+ ) ;
354
+ }
355
+ const instancesForRoot = helpers . findHostInstancesForRefresh (
356
+ root ,
357
+ families ,
358
+ ) ;
376
359
instancesForRoot . forEach ( inst => {
377
360
affectedInstances . add ( inst ) ;
378
361
} ) ;
@@ -397,11 +380,14 @@ export function injectIntoGlobalHook(globalObject: any): void {
397
380
// However, if there is no DevTools extension, we'll need to set up the global hook ourselves.
398
381
// Note that in this case it's important that renderer code runs *after* this method call.
399
382
// Otherwise, the renderer will think that there is no global hook, and won't do the injection.
383
+ let nextID = 0 ;
400
384
globalObject . __REACT_DEVTOOLS_GLOBAL_HOOK__ = hook = {
401
385
supportsFiber : true ,
402
- inject ( ) { } ,
386
+ inject ( injected ) {
387
+ return nextID ++ ;
388
+ } ,
403
389
onCommitFiberRoot (
404
- id : mixed ,
390
+ id : number ,
405
391
root : FiberRoot ,
406
392
maybePriorityLevel : mixed ,
407
393
didError : boolean ,
@@ -413,23 +399,31 @@ export function injectIntoGlobalHook(globalObject: any): void {
413
399
// Here, we just want to get a reference to scheduleRefresh.
414
400
const oldInject = hook . inject ;
415
401
hook . inject = function ( injected ) {
416
- findHostInstancesForRefresh = ( ( injected : any )
417
- . findHostInstancesForRefresh : FindHostInstancesForRefresh ) ;
418
- scheduleRefresh = ( ( injected : any ) . scheduleRefresh : ScheduleRefresh ) ;
419
- scheduleRoot = ( ( injected : any ) . scheduleRoot : ScheduleRoot ) ;
420
- setRefreshHandler = ( ( injected : any )
421
- . setRefreshHandler : SetRefreshHandler ) ;
422
- return oldInject . apply ( this , arguments ) ;
402
+ const id = oldInject . apply ( this , arguments ) ;
403
+ if (
404
+ typeof injected . scheduleRefresh === 'function' &&
405
+ typeof injected . setRefreshHandler === 'function'
406
+ ) {
407
+ // This version supports React Refresh.
408
+ helpersByRendererID . set ( id , ( ( injected : any ) : RendererHelpers ) ) ;
409
+ }
410
+ return id ;
423
411
} ;
424
412
425
413
// We also want to track currently mounted roots.
426
414
const oldOnCommitFiberRoot = hook . onCommitFiberRoot ;
427
415
hook . onCommitFiberRoot = function (
428
- id : mixed ,
416
+ id : number ,
429
417
root : FiberRoot ,
430
418
maybePriorityLevel : mixed ,
431
419
didError : boolean ,
432
420
) {
421
+ const helpers = helpersByRendererID . get ( id ) ;
422
+ if ( helpers === undefined ) {
423
+ return ;
424
+ }
425
+ helpersByRoot . set ( root , helpers ) ;
426
+
433
427
const current = root . current ;
434
428
const alternate = current . alternate ;
435
429
@@ -459,6 +453,8 @@ export function injectIntoGlobalHook(globalObject: any): void {
459
453
// We'll remount it on future edits.
460
454
// Remember what was rendered so we can restore it.
461
455
failedRoots . set ( root , alternate . memoizedState . element ) ;
456
+ } else {
457
+ helpersByRoot . delete ( root ) ;
462
458
}
463
459
} else if ( ! wasMounted && ! isMounted ) {
464
460
if ( didError && ! failedRoots . has ( root ) ) {
0 commit comments