Server Actionsはデータフェッチにも使える
Next.js においてデータフェッチの主なアプローチは Server Component 内でのデータフェッチです。
ただし、Server Component ではなく、Client Component 内でデータフェッチしたい場合もあると思います。そんなとき、Server Actions を Client Component から呼ぶことでデータフェッチできます。
Next.js のドキュメントでは、Server Actions はデータミューテーションのためのものと紹介されています。ただ、Server Actions の関数の戻り値は呼び出し側から参照することができます。よって、データフェッチの目的でも Server Actions を使うことが可能です。
具体的には、下記のようなコードで実現できます。
"use server";
export async function fetchDataAction() {
// ここでDBからデータ取得など...
return { message: "Hello, Hoge!" };
}
"use client";
import { useEffect, useState } from "react";
import { fetchDataAction } from "./fetchDataAction";
export function HogeClientComponent() {
const [message, setMessage] = useState("");
useEffect(() => {
fetchDataAction().then((data) => {
setMessage(data.message);
});
}, []);
return <div>message: {message}</div>;
}
HogeClientComponent
ではuseEffect
内で Server Actions でデータフェッチしています。従来、useEffect
内で Route Handler などへの HTTP リクエストを送っていた箇所を、Server Actions の呼び出しに変えただけです。
こうすることで、ClientComponent からデータフェッチしたいという目的のためにRoute Handler を定義して、それを fetch で呼び出すことをせずに、代わりにServer Actions を定義して、それを関数として呼び出すことができます。
ちなみに、useEffect
ではなく、SWR を使うこともできます。
"use client";
import useSWR from "swr";
import { fetchDataAction } from "./fetchDataAction";
export function HogeClientComponent() {
const { data, error, isLoading } = useSWR("fetchDataAction", fetchDataAction);
return <div>message: {data?.message}</div>;
}
実は、useEffect
内で Server Actions を呼び出すコード自体は Next.js のドキュメントで紹介されています。
// Next.js のドキュメントより引用
"use client";
import { incrementViews } from "./actions";
import { useState, useEffect } from "react";
export default function ViewCount({ initialViews }: { initialViews: number }) {
const [views, setViews] = useState(initialViews);
useEffect(() => {
const updateViews = async () => {
const updatedViews = await incrementViews();
setViews(updatedViews);
};
updateViews();
}, []);
return <p>Total Views: {views}</p>;
}
このサンプルコードでもincrementViews
の戻り値を参照していますが、incrementViews
の命名の通り、どちらかというとデータミューテーションとして紹介されています。
Server Actions はもちろんデータミューテーションに使えますが、先ほど説明した通り、ミューテートせずに、フェッチだけのために使うことも可能です。
Discussion
できるできないで言うとできるのですが、Next.jsの設計思想として「データ取得はRSCで」「mutationはServer Actionsで」という責務分離がなされてるので、あまり言及されてないものと私は認識しています。
なぜClient Componentsでデータフェッチしたいかによりますが、上述の例で言うと何かしらの理由で遅延させたいだけだと思うので、Next.jsにおいてこれはSuspendしてしまえばStreaming SSRによって遅延レンダリングにすることが可能です。
ちなみにServer ActionsはJSXを返すこともできるのですが、これはReactコアチームメンバーがXで「自己責任で」と言ってたので実質非推奨のようです。
関連discussion