React 19から useActionState
というServer Actionsを更に便利に使える新しい関数が登場します!
useActionState
は React 18までの useFormState
+ useFormStatus
を1つにまとめて便利に使えるようにした関数です!
useFormState と useFormStatus を使っていた際「1つにまとまっていたらいいのになぁ」と思っていました。
まさにな関数が登場してくれたので使い方を見ていきます!
記載時の 2024/6/8 時点で利用している、React 19・Next 15 はどちらもRC版です。
安定版として公開された際に使用方法が変更されている可能性がありますのでご留意下さい。
検証した環境
1 | next | 15.0.0-rc.0 |
2 | react | 19.0.0-rc-cc1ec60d0d-20240607 |
3 | react-dom | 19.0.0-rc-cc1ec60d0d-20240607 |
事前準備
React 19を使える環境の場合スキップして下さい
React 19が使えるNext.js 15のRC版を使えるようにします
npm install next@rc react@rc react-dom@rc
↑ではnpmを例としていますが、pnpmを使ったところ以下のように表示されました
dependencies:
- next 14.1.3
+ next 15.0.0-rc.0
- react 18.2.0
+ react 19.0.0-rc-cc1ec60d0d-20240607
- react-dom 18.2.0
+ react-dom 19.0.0-rc-cc1ec60d0d-20240607
また忘れてはいけないポイントとして、TypeScriptで使う型情報もReact 19のものを使えるようにする必要があります。
package.jsonを書き換えます
package.json
{
"dependencies": {
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc"
},
"overrides": {
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc"
}
}
React 19 RC Upgrade Guide – React
useActionStateを使う
以前Server Actionsのことを書いた際の処理を例に記載します
useFormState
+ useFormStatus
(before)
src/app/login/page.tsx
'use client'
import { login } from '@/actions/login'
import { useFormState, useFormStatus } from 'react-dom'
function SubmitButton() {
const { pending } = useFormStatus()
return (
<button type="submit" style={pending ? { opacity: '30%' } : {}} disabled={pending}>
{pending ? 'ログイン中...' : 'ログイン'}
</button>
)
}
export default function LoginPage() {
const [state, formAction] = useFormState(login, null)
return (
<div>
<h1>Login</h1>
<form action={formAction}>
<input type="text" placeholder="email" name="email" />
<input type="text" placeholder="password" name="password" />
<SubmitButton />
</form>
<div>{state?.validationErrors?.email?.join(',')}</div>
<div>{state?.validationErrors?.password?.join(',')}</div>
<div>{state?.serverError}</div>
</div>
)
}
useActionState
(after)
src/app/login/page.tsx
'use client'
import { useActionState } from 'react'
import { login } from '@/actions/login'
export default function LoginPage() {
const [state, formAction, isPending] = useActionState(login, null)
return (
<div>
<h1>Login</h1>
<form action={formAction}>
<input type="text" placeholder="email" name="email" />
<input type="text" placeholder="password" name="password" />
<button type="submit" style={isPending ? { opacity: '30%' } : {}} disabled={isPending}>
{isPending ? 'ログイン中...' : 'ログイン'}
</button>
</form>
<div>{state?.validationErrors?.email?.join(',')}</div>
<div>{state?.validationErrors?.password?.join(',')}</div>
<div>{state?.serverError}</div>
</div>
)
}
見比べると1まとめになったような関数というのが分かりやすいかと思います!
要点としては
useActionState
はuseFormState
でもアクションを実行している状態(pending)を判断出来るような関数useFormStatus
のように別コンポーネント化が不要に
この2点により「書きやすさ・分かりやすさ」がだいぶ向上したなと感じます。
useActionState と useFormState・useFormStatus の違い
細かい違いは箇条書きで記載しておきます
useActionState
はreact
の関数useFormState
・useFormStatus
はreact-dom
の関数
useActionState
はform以外でも使えるuseFormState
はform以外では使えない
- beforeの
<SubmitButton>
のように別コンポーネント化の必要性がなくなったuseFormStatus
はformタグを用いてるコンポーネントと別で定義する必要があった