From 0bfd4801e4293d7a484e6c2f40fda45cce09cbb5 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Sat, 16 Sep 2023 12:53:51 -0400 Subject: [PATCH] Restrict useFormState in Server Components (#55417) I based my changes on #49331, which did this for useFormStatus. While I was editing the file, I noticed that useOptimistic was incorrectly categorized as a `react-dom` package export, but it's actually exported from `react`. So I fixed that, too. Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com> --- .../crates/core/src/react_server_components.rs | 3 ++- .../server-graph/react-api/input.js | 2 ++ .../server-graph/react-api/output.js | 1 + .../server-graph/react-api/output.stderr | 7 +++++++ .../server-graph/react-dom-api/input.js | 2 +- .../server-graph/react-dom-api/output.js | 2 +- .../server-graph/react-dom-api/output.stderr | 14 +++++++------- .../server-graph-no-checks/react-dom-api/input.js | 2 +- .../server-graph-no-checks/react-dom-api/output.js | 3 ++- .../acceptance-app/server-components.test.ts | 13 +++---------- 10 files changed, 27 insertions(+), 22 deletions(-) diff --git a/packages/next-swc/crates/core/src/react_server_components.rs b/packages/next-swc/crates/core/src/react_server_components.rs index 6ba72beb90915..9c47c9af855c6 100644 --- a/packages/next-swc/crates/core/src/react_server_components.rs +++ b/packages/next-swc/crates/core/src/react_server_components.rs @@ -592,7 +592,7 @@ pub fn server_components( JsWord::from("flushSync"), JsWord::from("unstable_batchedUpdates"), JsWord::from("experimental_useFormStatus"), - JsWord::from("experimental_useOptimistic"), + JsWord::from("experimental_useFormState"), ], invalid_server_react_apis: vec![ JsWord::from("Component"), @@ -609,6 +609,7 @@ pub fn server_components( JsWord::from("useState"), JsWord::from("useSyncExternalStore"), JsWord::from("useTransition"), + JsWord::from("experimental_useOptimistic"), ], }) } diff --git a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/input.js b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/input.js index bec5b9683a33c..dff8deeb0bef6 100644 --- a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/input.js +++ b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/input.js @@ -16,6 +16,8 @@ import { useSyncExternalStore, } from 'react' +import { experimental_useOptimistic as useOptimistic } from 'react' + export default function () { return null } diff --git a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.js b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.js index 1a8c93cd6e0fc..2d242cc8bd6e8 100644 --- a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.js +++ b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.js @@ -2,6 +2,7 @@ import { useState } from 'react'; import { createContext } from 'react'; import { useEffect, useImperativeHandle } from 'react'; import { Component, createFactory, PureComponent, useDeferredValue, useInsertionEffect, useLayoutEffect, useReducer, useRef, useSyncExternalStore } from 'react'; +import { experimental_useOptimistic as useOptimistic } from 'react'; export default function() { return null; } diff --git a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.stderr b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.stderr index 38903b87918d7..2aaaa1da3054a 100644 --- a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.stderr +++ b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-api/output.stderr @@ -97,3 +97,10 @@ : ^^^^^^^^^^^^^^^^^^^^ 17 | } from 'react' `---- + + x NEXT_RSC_ERR_REACT_API: experimental_useOptimistic + ,-[input.js:18:1] + 18 | + 19 | import { experimental_useOptimistic as useOptimistic } from 'react' + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- diff --git a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/input.js b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/input.js index 722799c241272..d29c808451c59 100644 --- a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/input.js +++ b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/input.js @@ -1,8 +1,8 @@ import { findDOMNode, flushSync, unstable_batchedUpdates } from 'react-dom' import { - experimental_useOptimistic as useOptimistic, experimental_useFormStatus, + experimental_useFormState, } from 'react-dom' export default function () { diff --git a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.js b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.js index d7bf00f6bd08a..8df6e6178d5de 100644 --- a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.js +++ b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.js @@ -1,5 +1,5 @@ import { findDOMNode, flushSync, unstable_batchedUpdates } from 'react-dom'; -import { experimental_useOptimistic as useOptimistic, experimental_useFormStatus } from 'react-dom'; +import { experimental_useFormStatus, experimental_useFormState } from 'react-dom'; export default function() { return null; } diff --git a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.stderr b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.stderr index eb7a1b154f5e7..786dd9f145dc8 100644 --- a/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.stderr +++ b/packages/next-swc/crates/core/tests/errors/react-server-components/server-graph/react-dom-api/output.stderr @@ -17,18 +17,18 @@ : ^^^^^^^^^^^^^^^^^^^^^^^ `---- - x NEXT_RSC_ERR_REACT_API: experimental_useOptimistic + x NEXT_RSC_ERR_REACT_API: experimental_useFormStatus ,-[input.js:3:1] 3 | import { - 4 | experimental_useOptimistic as useOptimistic, + 4 | experimental_useFormStatus, : ^^^^^^^^^^^^^^^^^^^^^^^^^^ - 5 | experimental_useFormStatus, + 5 | experimental_useFormState, `---- - x NEXT_RSC_ERR_REACT_API: experimental_useFormStatus + x NEXT_RSC_ERR_REACT_API: experimental_useFormState ,-[input.js:4:1] - 4 | experimental_useOptimistic as useOptimistic, - 5 | experimental_useFormStatus, - : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 4 | experimental_useFormStatus, + 5 | experimental_useFormState, + : ^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | } from 'react-dom' `---- diff --git a/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/input.js b/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/input.js index 722799c241272..d29c808451c59 100644 --- a/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/input.js +++ b/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/input.js @@ -1,8 +1,8 @@ import { findDOMNode, flushSync, unstable_batchedUpdates } from 'react-dom' import { - experimental_useOptimistic as useOptimistic, experimental_useFormStatus, + experimental_useFormState, } from 'react-dom' export default function () { diff --git a/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/output.js b/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/output.js index d7bf00f6bd08a..9621b75b305da 100644 --- a/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/output.js +++ b/packages/next-swc/crates/core/tests/fixture/react-server-components/server-graph-no-checks/react-dom-api/output.js @@ -1,5 +1,6 @@ import { findDOMNode, flushSync, unstable_batchedUpdates } from 'react-dom'; -import { experimental_useOptimistic as useOptimistic, experimental_useFormStatus } from 'react-dom'; +import { experimental_useFormStatus, experimental_useFormState } from 'react-dom'; + export default function() { return null; } diff --git a/test/development/acceptance-app/server-components.test.ts b/test/development/acceptance-app/server-components.test.ts index 665c1a1d1ecfe..73d4776f5ada1 100644 --- a/test/development/acceptance-app/server-components.test.ts +++ b/test/development/acceptance-app/server-components.test.ts @@ -258,19 +258,12 @@ describe('Error Overlay for server components', () => { ) await check(async () => { - expect( - await browser - .waitForElementByCss('#nextjs__container_errors_desc') - .text() - ).toContain( - 'experimental_useOptimistic only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component' - ) + const html = await browser.eval('document.documentElement.innerHTML') + expect(html).toContain('experimental_useOptimistic') return 'success' }, 'success') - expect(next.cliOutput).toContain( - 'experimental_useOptimistic only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component' - ) + expect(next.cliOutput).toContain('experimental_useOptimistic') await cleanup() })