@@ -66,7 +66,7 @@ if (__DEV__) {
66
66
return self;
67
67
}
68
68
69
- var ReactVersion = "18.3.0-www-classic-09d28a0e ";
69
+ var ReactVersion = "18.3.0-www-classic-909c7c72 ";
70
70
71
71
var LegacyRoot = 0;
72
72
var ConcurrentRoot = 1;
@@ -6101,7 +6101,14 @@ if (__DEV__) {
6101
6101
}
6102
6102
}
6103
6103
6104
- var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we
6104
+ var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue;
6105
+
6106
+ function getThenablesFromState(state) {
6107
+ {
6108
+ var devState = state;
6109
+ return devState.thenables;
6110
+ }
6111
+ } // An error that is thrown (e.g. by `use`) to trigger Suspense. If we
6105
6112
// detect this is caught by userspace, we'll log a warning in development.
6106
6113
6107
6114
var SuspenseException = new Error(
@@ -6134,7 +6141,12 @@ if (__DEV__) {
6134
6141
function createThenableState() {
6135
6142
// The ThenableState is created the first time a component suspends. If it
6136
6143
// suspends again, we'll reuse the same state.
6137
- return [];
6144
+ {
6145
+ return {
6146
+ didWarnAboutUncachedPromise: false,
6147
+ thenables: []
6148
+ };
6149
+ }
6138
6150
}
6139
6151
function isThenableResolved(thenable) {
6140
6152
var status = thenable.status;
@@ -6148,16 +6160,45 @@ if (__DEV__) {
6148
6160
ReactCurrentActQueue$2.didUsePromise = true;
6149
6161
}
6150
6162
6151
- var previous = thenableState[index];
6163
+ var trackedThenables = getThenablesFromState(thenableState);
6164
+ var previous = trackedThenables[index];
6152
6165
6153
6166
if (previous === undefined) {
6154
- thenableState .push(thenable);
6167
+ trackedThenables .push(thenable);
6155
6168
} else {
6156
6169
if (previous !== thenable) {
6157
6170
// Reuse the previous thenable, and drop the new one. We can assume
6158
6171
// they represent the same value, because components are idempotent.
6159
- // Avoid an unhandled rejection errors for the Promises that we'll
6172
+ {
6173
+ var thenableStateDev = thenableState;
6174
+
6175
+ if (!thenableStateDev.didWarnAboutUncachedPromise) {
6176
+ // We should only warn the first time an uncached thenable is
6177
+ // discovered per component, because if there are multiple, the
6178
+ // subsequent ones are likely derived from the first.
6179
+ //
6180
+ // We track this on the thenableState instead of deduping using the
6181
+ // component name like we usually do, because in the case of a
6182
+ // promise-as-React-node, the owner component is likely different from
6183
+ // the parent that's currently being reconciled. We'd have to track
6184
+ // the owner using state, which we're trying to move away from. Though
6185
+ // since this is dev-only, maybe that'd be OK.
6186
+ //
6187
+ // However, another benefit of doing it this way is we might
6188
+ // eventually have a thenableState per memo/Forget boundary instead
6189
+ // of per component, so this would allow us to have more
6190
+ // granular warnings.
6191
+ thenableStateDev.didWarnAboutUncachedPromise = true; // TODO: This warning should link to a corresponding docs page.
6192
+
6193
+ error(
6194
+ "A component was suspended by an uncached promise. Creating " +
6195
+ "promises inside a Client Component or hook is not yet " +
6196
+ "supported, except via a Suspense-compatible library or framework."
6197
+ );
6198
+ }
6199
+ } // Avoid an unhandled rejection errors for the Promises that we'll
6160
6200
// intentionally ignore.
6201
+
6161
6202
thenable.then(noop, noop);
6162
6203
thenable = previous;
6163
6204
}
@@ -8259,7 +8300,7 @@ if (__DEV__) {
8259
8300
}
8260
8301
}
8261
8302
8262
- function warnIfAsyncClientComponent(Component, componentDoesIncludeHooks ) {
8303
+ function warnIfAsyncClientComponent(Component) {
8263
8304
{
8264
8305
// This dev-only check only works for detecting native async functions,
8265
8306
// not transpiled ones. There's also a prod check that we use to prevent
@@ -8271,43 +8312,20 @@ if (__DEV__) {
8271
8312
"[object AsyncFunction]";
8272
8313
8273
8314
if (isAsyncFunction) {
8274
- // Encountered an async Client Component. This is not yet supported,
8275
- // except in certain constrained cases, like during a route navigation.
8315
+ // Encountered an async Client Component. This is not yet supported.
8276
8316
var componentName = getComponentNameFromFiber(
8277
8317
currentlyRenderingFiber$1
8278
8318
);
8279
8319
8280
8320
if (!didWarnAboutAsyncClientComponent.has(componentName)) {
8281
- didWarnAboutAsyncClientComponent.add(componentName); // Check if this is a sync update. We use the "root" render lanes here
8282
- // because the "subtree" render lanes may include additional entangled
8283
- // lanes related to revealing previously hidden content.
8321
+ didWarnAboutAsyncClientComponent.add(componentName);
8284
8322
8285
- var root = getWorkInProgressRoot();
8286
- var rootRenderLanes = getWorkInProgressRootRenderLanes();
8287
-
8288
- if (root !== null && includesBlockingLane(root, rootRenderLanes)) {
8289
- error(
8290
- "async/await is not yet supported in Client Components, only " +
8291
- "Server Components. This error is often caused by accidentally " +
8292
- "adding `'use client'` to a module that was originally written " +
8293
- "for the server."
8294
- );
8295
- } else {
8296
- // This is a concurrent (Transition, Retry, etc) render. We don't
8297
- // warn in these cases.
8298
- //
8299
- // However, Async Components are forbidden to include hooks, even
8300
- // during a transition, so let's check for that here.
8301
- //
8302
- // TODO: Add a corresponding warning to Server Components runtime.
8303
- if (componentDoesIncludeHooks) {
8304
- error(
8305
- "Hooks are not supported inside an async component. This " +
8306
- "error is often caused by accidentally adding `'use client'` " +
8307
- "to a module that was originally written for the server."
8308
- );
8309
- }
8310
- }
8323
+ error(
8324
+ "async/await is not yet supported in Client Components, only " +
8325
+ "Server Components. This error is often caused by accidentally " +
8326
+ "adding `'use client'` to a module that was originally written " +
8327
+ "for the server."
8328
+ );
8311
8329
}
8312
8330
}
8313
8331
}
@@ -8390,6 +8408,7 @@ if (__DEV__) {
8390
8408
8391
8409
ignorePreviousDependencies =
8392
8410
current !== null && current.type !== workInProgress.type;
8411
+ warnIfAsyncClientComponent(Component);
8393
8412
}
8394
8413
8395
8414
workInProgress.memoizedState = null;
@@ -8482,16 +8501,13 @@ if (__DEV__) {
8482
8501
}
8483
8502
}
8484
8503
8485
- finishRenderingHooks(current, workInProgress, Component );
8504
+ finishRenderingHooks(current, workInProgress);
8486
8505
return children;
8487
8506
}
8488
8507
8489
8508
function finishRenderingHooks(current, workInProgress, Component) {
8490
8509
{
8491
8510
workInProgress._debugHookTypes = hookTypesDev;
8492
- var componentDoesIncludeHooks =
8493
- workInProgressHook !== null || thenableIndexCounter !== 0;
8494
- warnIfAsyncClientComponent(Component, componentDoesIncludeHooks);
8495
8511
} // We can assume the previous dispatcher is always this one, since we set it
8496
8512
// at the beginning of the render phase and there's no re-entrance.
8497
8513
@@ -8615,7 +8631,7 @@ if (__DEV__) {
8615
8631
props,
8616
8632
secondArg
8617
8633
);
8618
- finishRenderingHooks(current, workInProgress, Component );
8634
+ finishRenderingHooks(current, workInProgress);
8619
8635
return children;
8620
8636
}
8621
8637
0 commit comments