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>
This commit is contained in:
Andrew Clark 2023-09-16 12:53:51 -04:00 committed by GitHub
parent 676e3aeb6d
commit 0bfd4801e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 27 additions and 22 deletions

View file

@ -592,7 +592,7 @@ pub fn server_components<C: Comments>(
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<C: Comments>(
JsWord::from("useState"),
JsWord::from("useSyncExternalStore"),
JsWord::from("useTransition"),
JsWord::from("experimental_useOptimistic"),
],
})
}

View file

@ -16,6 +16,8 @@ import {
useSyncExternalStore,
} from 'react'
import { experimental_useOptimistic as useOptimistic } from 'react'
export default function () {
return null
}

View file

@ -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;
}

View file

@ -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'
: ^^^^^^^^^^^^^^^^^^^^^^^^^^
`----

View file

@ -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 () {

View file

@ -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;
}

View file

@ -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'
`----

View file

@ -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 () {

View file

@ -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;
}

View file

@ -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()
})