Server Actionsとは?
Next.js13.4から導入された機能で、14.0から安定版になりました。
従来までであればformのsubmitは基本的にブラウザ上で実行されるアクションになっていました。これを使うとsubmitをサーバー側で実行することができるようになります。
メリット
シームレスにサーバーとクライアント間の実装を行える。
一つのソースにサーバーとクライアントのソースが混在することになる。
クライアント側のJavaScriptの削減
クライアント側にsubmit関数の処理を入れる場合e.preventDefaultだったり、e.taget.valueだったり、HTTPヘッダーの設定だったりクライアント側からサーバー側に送信するために余計なコードが増えることになります。ただ、サーバー側の処理であればそうしためんどくさい手続きが不要になります。
inputタグの属性が簡潔になる。
valueとonChangeなどは不要になる。FormDataという型に入るようになる。
APIの実行回数、レンダリング回数が減る。
サーバー側の処理をそのまま実行できるので。
デメリット
関心の分離ができない。
フロントのコードとバックエンドのコードが一つになる。また従来の開発に戻ってしまっているとの懸念も言われる。
実装
サーバーコンポーネントでも使うことはできますが、基本的にはformはクライアント側の処理が多いのでclientコンポーネントで使うケースが多くなると思います。
server actionsを使った場合の特徴としてはsubmit関数は全て非同期関数(asyncをつけることになる)になります。
サーバーコンポーネント
submit時の処理において'use server'という目印をつけます。実際に動くのはバックエンドで動いているNext.js側の処理になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
export default function Page() { // Server Action async function create(formData: FormData) { 'use server' // submit後の処理 const title = formData.get("title"); // input属性のnameに指定したキーを指定すると取得できる。 } return ( <form action={async (formData) => {await create(formData)}}> <input type="text" name="title" /> <button type="submit" /> // valueとonChangeが不要になる。 </form> ) } |
クライアントコンポーネント
サーバーコンポーネントのように同じファイルにsubmit関数を書くとエラーになってしまうので別ファイルにactionsという形で書き出します。
actions
1 2 3 4 5 |
'use server' export async function create() { // ... } |
呼び出し側
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
"use client" import { create } from '@/app/actions' export function Button() { const [count,setCount] = useState(0); const serverAction = async () => { const res = await create(); // ここだけがサーバー側の処理になる。 setCount(count+1); // clientコンポーネントであればここでclientコンポーネントでしか使えないuseStateなどの処理を呼び出せる。 } return ( <form action={serverAction}> <button type="submit" /> </form> ) } |
データの更新
実際にデータを更新した値でrefetchしなきゃいけない場合は特有の関数を呼ぶことになります。これらを使うことでsubmit時に更新したデータがUIに反映されることになります。
revalidateTag
事前にfetchする関数にタグを登録しておく方式。モデルとかドメインごとにrefetchしたい場合はこれを使う。
fetch関数側
1 |
fetch('パス',{next: {tags: ['a','b','c']}}) |
ちなみに、prismaとかsupabaseなどサードパーティ製のfetchライブラリを使う場合は当然この書き方ができなくなるので使えなくなるので注意。revalidatePathの方を使う。
server actions側
1 |
revalidateTag('a') |
revalidatePath
これなら事前登録は不要。個人的にはこちらの方が良さそうです。
1 |
revalidatePath('パス','layout') |
第二引数にlayoutと指定してあげることでlayoutコンポーネントの方もrefetchしてくれます。
この記事へのコメントはありません。