🔖
【Next.js】Server ActionsとuseStateやuseEffectを組み合わせるサンプル
Next.jsのServer Actionsがstableになったということなのでその簡単なサンプルです。
※ Next.jsは初心者なので変な箇所あれば指摘いただけるとありがたいです。
バージョン
next: "14.0.0"
typescript: "5.2.2"
コード
- server actionsの関数を定義したファイルを
app/server_actions.tsx
として作成 - create-next-appで作成したアプリのpage.tsxを変更
- 確認用にconsole.log適当に入れています
server actionsの定義はinit用とform action用にそれぞれ定義して適当にレスポンス変えています。
app/page.tsx
'use server'
export async function initServerAction(): Promise<ActionResponse> {
console.log('=== server: initServerAction ===')
return { action: 'init' }
}
interface ActionResponse {
action: string
name?: string
}
export async function postServerAction(
formData: FormData,
): Promise<ActionResponse> {
console.log('=== server: postServerAction ===')
const name = formData.get('name')?.toString() ?? ''
return { action: 'post', name }
}
先頭の'use client'
をつけることでclient componentとして扱われます。(本来のapp/page.tsxはserver componentにするのだと思いますが、サンプルのため)
app/page.tsx
'use client'
import { useEffect, useState } from 'react'
import { initServerAction, postServerAction } from './server_actions'
export default function Home() {
const [action, setAction] = useState<string>()
const [name, setName] = useState<string>()
useEffect(() => {
;(async () => {
console.log('=== client: init ===')
const res = await initServerAction()
setAction(res.action)
console.log(res)
})()
}, [])
const callServerAction = async (formData: FormData) => {
console.log('=== client: callServerAction ===')
const res = await postServerAction(formData)
setAction(res.action)
setName(res.name)
console.log(res)
}
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div>
<form action={callServerAction}>
<input style={{ color: 'black' }} type="text" name="name" />
<button type="submit">Submit</button>
</form>
<div>
<span>name: </span>
<span>{name}</span>
</div>
<div>
<span>actin: </span>
<span>{action}</span>
</div>
</div>
</main>
)
}
ページを表示したら画面側のコンソールとサーバのログにそれぞれ表示されるはずです。
memo
今回のコードに関するちょっとしたメモです。
useStateやuseEffectはclient componentに定義
当たり前ですが、useStateやuseEffectはserver componentでは使えないので、これらを使うにはclient componentとして定義する必要があります。
client componentにserver actionsは定義できない
server actionsをclient componentに定義すると以下のようなエラーメッセージが出力されます。server actionsをclient componentから呼び出すには別ファイルに切り出してねとのこと。
なので今回のサンプルではapp/server_actions.tsx
に切り出しています
It is not allowed to define inline "use server" annotated Server Actions in Client Components.
To use Server Actions in a Client Component, you can either export them from a separate file with "use server" at the top, or pass them down through props from a Server Component.
Discussion