diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js
index 945051d3d1b2a..611554594fc8d 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.js
@@ -220,6 +220,10 @@ function updateForwardRef(
nextProps: any,
renderExpirationTime: ExpirationTime,
) {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens after the first render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
if (__DEV__) {
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
@@ -415,6 +419,10 @@ function updateSimpleMemoComponent(
updateExpirationTime,
renderExpirationTime: ExpirationTime,
): null | Fiber {
+ // TODO: current can be non-null here even if the component
+ // hasn't yet mounted. This happens when the inner render suspends.
+ // We'll need to figure out if this is fine or can cause issues.
+
if (__DEV__) {
if (workInProgress.type !== workInProgress.elementType) {
// Lazy component props can't be validated in createElement
diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js
index 6eceed84f7e41..0b5f0172e7ea1 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.js
@@ -449,17 +449,6 @@ function mountWorkInProgressHook(): Hook {
if (__DEV__) {
(hook: any)._debugType = (currentHookNameInDev: any);
- if (
- currentlyRenderingFiber !== null &&
- currentlyRenderingFiber.alternate !== null
- ) {
- warning(
- false,
- '%s: Rendered more hooks than during the previous render. This is ' +
- 'not currently supported and may lead to unexpected behavior.',
- getComponentName(currentlyRenderingFiber.type),
- );
- }
}
if (workInProgressHook === null) {
// This is the first hook in the list
diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
index 0ed4014dfb29e..f7ab26011b64e 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
@@ -1366,4 +1366,97 @@ describe('ReactHooks', () => {
),
).toThrow('Hello');
});
+
+ // Regression test for https://github.com/facebook/react/issues/14790
+ it('does not fire a false positive warning when suspending memo', async () => {
+ const {Suspense, useState} = React;
+
+ let wasSuspended = false;
+ function trySuspend() {
+ if (!wasSuspended) {
+ throw new Promise(resolve => {
+ wasSuspended = true;
+ resolve();
+ });
+ }
+ }
+
+ function Child() {
+ useState();
+ trySuspend();
+ return 'hello';
+ }
+
+ const Wrapper = React.memo(Child);
+ const root = ReactTestRenderer.create(
+
+
+ ,
+ );
+ expect(root).toMatchRenderedOutput('loading');
+ await Promise.resolve();
+ expect(root).toMatchRenderedOutput('hello');
+ });
+
+ // Regression test for https://github.com/facebook/react/issues/14790
+ it('does not fire a false positive warning when suspending forwardRef', async () => {
+ const {Suspense, useState} = React;
+
+ let wasSuspended = false;
+ function trySuspend() {
+ if (!wasSuspended) {
+ throw new Promise(resolve => {
+ wasSuspended = true;
+ resolve();
+ });
+ }
+ }
+
+ function render(props, ref) {
+ useState();
+ trySuspend();
+ return 'hello';
+ }
+
+ const Wrapper = React.forwardRef(render);
+ const root = ReactTestRenderer.create(
+
+
+ ,
+ );
+ expect(root).toMatchRenderedOutput('loading');
+ await Promise.resolve();
+ expect(root).toMatchRenderedOutput('hello');
+ });
+
+ // Regression test for https://github.com/facebook/react/issues/14790
+ it('does not fire a false positive warning when suspending memo(forwardRef)', async () => {
+ const {Suspense, useState} = React;
+
+ let wasSuspended = false;
+ function trySuspend() {
+ if (!wasSuspended) {
+ throw new Promise(resolve => {
+ wasSuspended = true;
+ resolve();
+ });
+ }
+ }
+
+ function render(props, ref) {
+ useState();
+ trySuspend();
+ return 'hello';
+ }
+
+ const Wrapper = React.memo(React.forwardRef(render));
+ const root = ReactTestRenderer.create(
+
+
+ ,
+ );
+ expect(root).toMatchRenderedOutput('loading');
+ await Promise.resolve();
+ expect(root).toMatchRenderedOutput('hello');
+ });
});