@@ -299,6 +299,7 @@ type SuspenseNode = {
299
299
nextSibling : null | SuspenseNode ,
300
300
rects : null | Array < Rect > , // The bounding rects of content children.
301
301
suspendedBy : Map < ReactIOInfo , Set < DevToolsInstance> > , // Tracks which data we're suspended by and the children that suspend it.
302
+ environments : Map < string , number> , // Tracks the Flight environment names that suspended this. I.e. if the server blocked this.
302
303
// Track whether any of the items in suspendedBy are unique this this Suspense boundaries or if they're all
303
304
// also in the parent sets. This determine whether this could contribute in the loading sequence.
304
305
hasUniqueSuspenders : boolean ,
@@ -327,6 +328,7 @@ function createSuspenseNode(
327
328
nextSibling : null ,
328
329
rects : null ,
329
330
suspendedBy : new Map ( ) ,
331
+ environments : new Map ( ) ,
330
332
hasUniqueSuspenders : false ,
331
333
hasUnknownSuspenders : false ,
332
334
} ) ;
@@ -2220,6 +2222,10 @@ export function attach(
2220
2222
}
2221
2223
operations[i++] = fiberIdWithChanges;
2222
2224
operations[i++] = suspense.hasUniqueSuspenders ? 1 : 0;
2225
+ operations[i++] = suspense.environments.size;
2226
+ suspense.environments.forEach((count, env) => {
2227
+ operations[i++] = getStringID(env);
2228
+ });
2223
2229
});
2224
2230
}
2225
2231
@@ -2725,6 +2731,13 @@ export function attach(
2725
2731
return;
2726
2732
}
2727
2733
2734
+ // TODO: Just enqueue the operations here instead of stashing by id.
2735
+
2736
+ // Ensure each environment gets recorded in the string table since it is emitted
2737
+ // before we loop it over again later during flush.
2738
+ suspenseNode.environments.forEach((count, env) => {
2739
+ getStringID(env);
2740
+ });
2728
2741
pendingSuspenderChanges.add(fiberInstance.id);
2729
2742
}
2730
2743
@@ -2807,7 +2820,20 @@ export function attach(
2807
2820
let suspendedBySet = suspenseNodeSuspendedBy.get(ioInfo);
2808
2821
if (suspendedBySet === undefined) {
2809
2822
suspendedBySet = new Set();
2810
- suspenseNodeSuspendedBy.set(asyncInfo.awaited, suspendedBySet);
2823
+ suspenseNodeSuspendedBy.set(ioInfo, suspendedBySet);
2824
+ // We've added a dependency. We must increment the ref count of the environment.
2825
+ const env = ioInfo.env;
2826
+ if (env != null) {
2827
+ const environmentCounts = parentSuspenseNode.environments;
2828
+ const count = environmentCounts.get(env);
2829
+ if (count === undefined || count === 0) {
2830
+ environmentCounts.set(env, 1);
2831
+ // We've discovered a new environment for this SuspenseNode. We'll to update the node.
2832
+ recordSuspenseSuspenders(parentSuspenseNode);
2833
+ } else {
2834
+ environmentCounts.set(env, count + 1);
2835
+ }
2836
+ }
2811
2837
}
2812
2838
// The child of the Suspense boundary that was suspended on this, or null if suspended at the root.
2813
2839
// This is used to keep track of how many dependents are still alive and also to get information
@@ -2897,6 +2923,7 @@ export function attach(
2897
2923
: instance.suspenseNode;
2898
2924
if (previousSuspendedBy !== null && suspenseNode !== null) {
2899
2925
const nextSuspendedBy = instance.suspendedBy;
2926
+ let changedEnvironment = false;
2900
2927
for (let i = 0; i < previousSuspendedBy.length; i++) {
2901
2928
const asyncInfo = previousSuspendedBy[i];
2902
2929
if (
@@ -2935,7 +2962,26 @@ export function attach(
2935
2962
}
2936
2963
}
2937
2964
if (suspendedBySet !== undefined && suspendedBySet.size === 0) {
2938
- suspenseNode.suspendedBy.delete(asyncInfo.awaited);
2965
+ suspenseNode.suspendedBy.delete(ioInfo);
2966
+ // Successfully removed all dependencies. We can decrement the ref count of the environment.
2967
+ const env = ioInfo.env;
2968
+ if (env != null) {
2969
+ const environmentCounts = suspenseNode.environments;
2970
+ const count = environmentCounts.get(env);
2971
+ if (count === undefined || count === 0) {
2972
+ throw new Error(
2973
+ 'We are removing an environment but it was not in the set. ' +
2974
+ 'This is a bug in React.',
2975
+ );
2976
+ }
2977
+ if (count === 1) {
2978
+ environmentCounts.delete(env);
2979
+ // Last one. We've now change the set of environments. We'll need to update the node.
2980
+ changedEnvironment = true;
2981
+ } else {
2982
+ environmentCounts.set(env, count - 1);
2983
+ }
2984
+ }
2939
2985
}
2940
2986
if (
2941
2987
suspenseNode.hasUniqueSuspenders &&
@@ -2948,6 +2994,9 @@ export function attach(
2948
2994
}
2949
2995
}
2950
2996
}
2997
+ if (changedEnvironment) {
2998
+ recordSuspenseSuspenders(suspenseNode);
2999
+ }
2951
3000
}
2952
3001
}
2953
3002
0 commit comments