Skip to content

Commit f115409

Browse files
authored
Handle changes at module boundaries (facebook#16002)
1 parent 915dfe6 commit f115409

File tree

2 files changed

+375
-12
lines changed

2 files changed

+375
-12
lines changed

packages/react-refresh/src/ReactFreshRuntime.js

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,18 @@ if (!__DEV__) {
3737

3838
// In old environments, we'll leak previous types after every edit.
3939
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
40-
const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
4140

4241
// We never remove these associations.
4342
// It's OK to reference families, but use WeakMap/Set for types.
4443
const allFamiliesByID: Map<string, Family> = new Map();
45-
// $FlowIssue
46-
const allTypes: WeakSet<any> | Set<any> = new PossiblyWeakSet();
44+
const allFamiliesByType: // $FlowIssue
45+
WeakMap<any, Family> | Map<any, Family> = new PossiblyWeakMap();
4746
const allSignaturesByType: // $FlowIssue
4847
WeakMap<any, Signature> | Map<any, Signature> = new PossiblyWeakMap();
4948
// This WeakMap is read by React, so we only put families
5049
// that have actually been edited here. This keeps checks fast.
5150
// $FlowIssue
52-
const familiesByType: // $FlowIssue
51+
const updatedFamiliesByType: // $FlowIssue
5352
WeakMap<any, Family> | Map<any, Family> = new PossiblyWeakMap();
5453

5554
// This is cleared on every performReactRefresh() call.
@@ -145,7 +144,8 @@ function canPreserveStateBetween(prevType, nextType) {
145144
}
146145

147146
function resolveFamily(type) {
148-
return familiesByType.get(type);
147+
// Only check updated types to keep lookups fast.
148+
return updatedFamiliesByType.get(type);
149149
}
150150

151151
export function performReactRefresh(): RefreshUpdate | null {
@@ -163,8 +163,8 @@ export function performReactRefresh(): RefreshUpdate | null {
163163
// Now that we got a real edit, we can create associations
164164
// that will be read by the React reconciler.
165165
const prevType = family.current;
166-
familiesByType.set(prevType, family);
167-
familiesByType.set(nextType, family);
166+
updatedFamiliesByType.set(prevType, family);
167+
updatedFamiliesByType.set(nextType, family);
168168
family.current = nextType;
169169

170170
// Determine whether this should be a re-render or a re-mount.
@@ -266,11 +266,9 @@ export function register(type: any, id: string): void {
266266
// This can happen in an edge case, e.g. if we register
267267
// return value of a HOC but it returns a cached component.
268268
// Ignore anything but the first registration for each type.
269-
if (allTypes.has(type)) {
269+
if (allFamiliesByType.has(type)) {
270270
return;
271271
}
272-
allTypes.add(type);
273-
274272
// Create family or remember to update it.
275273
// None of this bookkeeping affects reconciliation
276274
// until the first performReactRefresh() call above.
@@ -281,6 +279,7 @@ export function register(type: any, id: string): void {
281279
} else {
282280
pendingUpdates.push([family, type]);
283281
}
282+
allFamiliesByType.set(type, family);
284283

285284
// Visit inner types because we might not have registered them.
286285
if (typeof type === 'object' && type !== null) {
@@ -345,6 +344,16 @@ export function getFamilyByID(id: string): Family | void {
345344
}
346345
}
347346

347+
export function getFamilyByType(type: any): Family | void {
348+
if (__DEV__) {
349+
return allFamiliesByType.get(type);
350+
} else {
351+
throw new Error(
352+
'Unexpected call to React Refresh in a production environment.',
353+
);
354+
}
355+
}
356+
348357
export function findAffectedHostInstances(
349358
families: Array<Family>,
350359
): Set<Instance> {

0 commit comments

Comments
 (0)