Server Actions must be async の直し方
実際に出るエラー
use server を付けた関数に async が付いていないときに出るビルドエラーです。
文言は3種類ある
同じ原因でも、どこに書いたか、何を export したかで出る文言が変わります。実機で確かめた3つです。
| 書いたもの | 出る文言 |
|---|---|
| 関数の中の use server・async なし | Server Actions must be async functions. |
| ファイルから数値や文字列を export | Only async functions are allowed to be exported… |
| ファイルからオブジェクトを export | A "use server" file can only export async functions, found object. |
検索するときは、自分の手元に出た文言で探してください。1つだけ覚えていると、別の文言に当たったときに別の問題だと思ってしまいます。
1つめ:async が付いていない
export default function Page() {
function save(formData: FormData) {
'use server'
console.log(formData.get('a'))
}
return <form action={save}><input name="a" /></form>
}
Error: Server Actions must be async functions.
中で await していなくても async が要ります。呼ぶ側から見ると、この関数は常にネットワークを越えます。結果は必ずあとから返るので、戻り値が Promise であることが形として決まっています。
2つめ:関数以外を export している
'use server'
export const LIMIT = 10
export async function save(formData: FormData) {
console.log(formData.get('a'))
}
Error: Only async functions are allowed to be exported in a "use server" file.
save は async なのに落ちます。落としているのは LIMIT のほうです。
なぜ関数だけなのか
use server と書いたファイルの export は、ブラウザから呼べる入口として登録されます。
use server のファイル
export async function save()
export async function remove()
ブラウザ側
フォームの action
ボタンの中から呼ぶ
越えられる: FormData・文字列・数値
越えられない: 定数(LIMIT)
越えられない: 型定義
越えられない: ふつうの関数
入口になれるのは呼び出せるものだけです。定数や型が混ざると、ファイル全体として条件を満たしません。1つでも関数以外があれば止まります。
直し方
置き場所を3つに分けます。
app/
actions.ts 'use server'。async 関数だけ
limits.ts 定数と型。印は付けない
page.tsx 画面。両方から読む
import { save } from './actions'
import { LIMIT } from './limits'
export default function Page() {
return (
<form action={save}>
<input name="a" maxLength={LIMIT} />
</form>
)
}
実機で確かめました。この形でビルドは通り、ページは事前に描かれたままです。送信先を持っていること自体は、そのページを動的にしません(キャッシュの考え方)。
関数の中とファイルの先頭は、効く範囲が違う
関数の中に書く
function save() { 'use server' // この関数1つだけ }
外側の関数には掛からない。定数の制限も無い。
ファイルの先頭に書く
'use server' // このファイルの export 全部
export したもの全部が対象。関数以外は置けない。
送信先が増えるなら、ファイルの先頭に書く形のほうが整理しやすくなります。そのぶん、定数を一緒に置けないという制限が付いてきます。
出典
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。