Replace useFormStatus and useFormState with useActionState (#748)

This commit is contained in:
Delba de Oliveira
2024-06-19 09:41:51 +01:00
committed by GitHub
parent deca7c766f
commit de76b00263
8 changed files with 100 additions and 86 deletions

View File

@@ -24,7 +24,6 @@ const FormSchema = z.object({
const CreateInvoice = FormSchema.omit({ id: true, date: true });
const UpdateInvoice = FormSchema.omit({ date: true, id: true });
// This is temporary
export type State = {
errors?: {
customerId?: string[];

View File

@@ -10,14 +10,14 @@ import {
} from '@heroicons/react/24/outline';
import { Button } from '@/app/ui/button';
import { createInvoice, State } from '@/app/lib/actions';
import { useFormState } from 'react-dom';
import { useActionState } from 'react';
export default function Form({ customers }: { customers: CustomerField[] }) {
const initialState: State = { message: null, errors: {} };
const [state, dispatch] = useFormState(createInvoice, initialState);
const [state, formAction] = useActionState(createInvoice, initialState);
return (
<form action={dispatch}>
<form action={formAction}>
<div className="rounded-md bg-gray-50 p-4 md:p-6">
{/* Customer Name */}
<div className="mb-4">

View File

@@ -10,7 +10,7 @@ import {
import Link from 'next/link';
import { Button } from '@/app/ui/button';
import { updateInvoice, State } from '@/app/lib/actions';
import { useFormState } from 'react-dom';
import { useActionState } from 'react';
export default function EditInvoiceForm({
invoice,
@@ -21,10 +21,10 @@ export default function EditInvoiceForm({
}) {
const initialState: State = { message: null, errors: {} };
const updateInvoiceWithId = updateInvoice.bind(null, invoice.id);
const [state, dispatch] = useFormState(updateInvoiceWithId, initialState);
const [state, formAction] = useActionState(updateInvoiceWithId, initialState);
return (
<form action={dispatch}>
<form action={formAction}>
<div className="rounded-md bg-gray-50 p-4 md:p-6">
{/* Customer Name */}
<div className="mb-4">

View File

@@ -9,13 +9,16 @@ import {
} from '@heroicons/react/24/outline';
import { ArrowRightIcon } from '@heroicons/react/20/solid';
import { Button } from './button';
import { useFormState, useFormStatus } from 'react-dom';
import { useActionState } from 'react';
export default function LoginForm() {
const [errorMessage, dispatch] = useFormState(authenticate, undefined);
const [errorMessage, formAction, isPending] = useActionState(
authenticate,
undefined,
);
return (
<form action={dispatch} className="space-y-3">
<form action={formAction} className="space-y-3">
<div className="flex-1 rounded-lg bg-gray-50 px-6 pb-4 pt-8">
<h1 className={`${lusitana.className} mb-3 text-2xl`}>
Please log in to continue.
@@ -61,7 +64,9 @@ export default function LoginForm() {
</div>
</div>
</div>
<LoginButton />
<Button className="mt-4 w-full" aria-disabled={isPending}>
Log in <ArrowRightIcon className="ml-auto h-5 w-5 text-gray-50" />
</Button>
<div
className="flex h-8 items-end space-x-1"
aria-live="polite"
@@ -78,13 +83,3 @@ export default function LoginForm() {
</form>
);
}
function LoginButton() {
const { pending } = useFormStatus();
return (
<Button className="mt-4 w-full" aria-disabled={pending}>
Log in <ArrowRightIcon className="ml-auto h-5 w-5 text-gray-50" />
</Button>
);
}

View File

@@ -29,8 +29,8 @@
},
"devDependencies": {
"@types/bcrypt": "^5.0.1",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.14",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"@vercel/style-guide": "^5.0.1",
"dotenv": "^16.3.1",
"eslint": "^8.52.0",

View File

@@ -59,11 +59,11 @@ devDependencies:
specifier: ^5.0.1
version: 5.0.2
'@types/react':
specifier: 18.2.21
version: 18.2.21
specifier: 18.3.3
version: 18.3.3
'@types/react-dom':
specifier: 18.2.14
version: 18.2.14
specifier: 18.3.0
version: 18.3.0
'@vercel/style-guide':
specifier: ^5.0.1
version: 5.2.0(eslint@8.57.0)(prettier@3.3.2)(typescript@5.2.2)
@@ -844,24 +844,19 @@ packages:
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
dev: true
/@types/react-dom@18.2.14:
resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==}
/@types/react-dom@18.3.0:
resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==}
dependencies:
'@types/react': 18.2.21
'@types/react': 18.3.3
dev: true
/@types/react@18.2.21:
resolution: {integrity: sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==}
/@types/react@18.3.3:
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
dependencies:
'@types/prop-types': 15.7.12
'@types/scheduler': 0.23.0
csstype: 3.1.3
dev: true
/@types/scheduler@0.23.0:
resolution: {integrity: sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==}
dev: true
/@types/semver@7.5.8:
resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
dev: true
@@ -1166,7 +1161,7 @@ packages:
eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1)
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint@8.57.0)(typescript@5.2.2)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-playwright: 0.16.0(eslint-plugin-jest@27.9.0)(eslint@8.57.0)
@@ -1955,7 +1950,7 @@ packages:
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-react: 7.34.2(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
@@ -1980,7 +1975,7 @@ packages:
peerDependencies:
eslint-plugin-import: '>=1.4.0'
dependencies:
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
dev: true
/eslint-import-resolver-node@0.3.9:
@@ -2004,7 +1999,7 @@ packages:
enhanced-resolve: 5.17.0
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
is-core-module: 2.13.1
@@ -2027,7 +2022,7 @@ packages:
enhanced-resolve: 5.17.0
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
is-core-module: 2.13.1
@@ -2039,6 +2034,36 @@ packages:
- supports-color
dev: true
/eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint:
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.2.2)
debug: 3.2.7
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
transitivePeerDependencies:
- supports-color
dev: true
/eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
engines: {node: '>=4'}
@@ -2138,6 +2163,41 @@ packages:
ignore: 5.3.1
dev: true
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.2.2)
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
array.prototype.flat: 1.3.2
array.prototype.flatmap: 1.3.2
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
hasown: 2.0.2
is-core-module: 2.13.1
is-glob: 4.0.3
minimatch: 3.1.2
object.fromentries: 2.0.8
object.groupby: 1.0.3
object.values: 1.2.0
semver: 6.3.1
tsconfig-paths: 3.15.0
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: true
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0):
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
engines: {node: '>=4'}
@@ -2173,41 +2233,6 @@ packages:
- supports-color
dev: true
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.2.2)
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
array.prototype.flat: 1.3.2
array.prototype.flatmap: 1.3.2
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
hasown: 2.0.2
is-core-module: 2.13.1
is-glob: 4.0.3
minimatch: 3.1.2
object.fromentries: 2.0.8
object.groupby: 1.0.3
object.values: 1.2.0
semver: 6.3.1
tsconfig-paths: 3.15.0
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: true
/eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint@8.57.0)(typescript@5.2.2):
resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}

View File

@@ -55,7 +55,9 @@ export default function LoginForm() {
</div>
</div>
</div>
<LoginButton />
<Button className="mt-4 w-full">
Log in <ArrowRightIcon className="ml-auto h-5 w-5 text-gray-50" />
</Button>
<div className="flex h-8 items-end space-x-1">
{/* Add form errors here */}
</div>
@@ -63,11 +65,3 @@ export default function LoginForm() {
</form>
);
}
function LoginButton() {
return (
<Button className="mt-4 w-full">
Log in <ArrowRightIcon className="ml-auto h-5 w-5 text-gray-50" />
</Button>
);
}

View File

@@ -1,4 +1,5 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default nextConfig;