https://zenn.dev/did0es/articles/cb8675f2b9da37
Next.jsでフロントエンドを作っているプロジェクトにSWRを導入した際に「SWRかgetServerSidePropsのどちらでデータ取得をすればいいのか迷う」みたいな意見があったので、チームで方針を作ったときに考えたことの話。
フロントエンドの構成については、バックエンドのREST APIを叩きに行ってデータを取得・更新する至って普通の構成。ただユーザーの認証をする必要があり、sessionの有無を見つつページの出し分けとかAPIの取得をする形になっている。認証部分はAWSのCognitoでクライアントにはnext-authを使用した。
データ取得・更新について、基本的にSWRを使用する方針にした。SWRについては周知の通りキャッシュ機構で高速にデータの表示ができるので使わない手は無いと思う。
また、next-authのuseSession
を使ってsession(に含まれるtoken)の有無を検証してからAPIコールするように fetcher を実装したので、SWRと合わせるとクライアントサイドで完結する(getServerSideProps
にデータ取得中と後のコンポーネントの出し分けをグダグダ書かないで済む)のも良い。
じゃあ全部SWRでやろうね!となるのだが...
以下のような認証後のページの出し分けはクライアントサイドで処理しないほうがいいので getServerSideProps
を使う。
/auth
からログイン、Cognitoのページにリダイレクトして認証/auth
にリダイレクト
/
に/auth/signup
に以上のフローの際に Cognito からのリダイレクトで/auth
を開き直すので、ページが再度読み込まれる。
ここで以下のようにSWRによってプロフィールを取得、有無を検証してリダイレクトを実装すると一瞬 /auth
ページが見えたり、profileがまだ取得できずrevalidateを待つ前にリダイレクトが走って予期せぬUIを表示したりする。
// 🙅♂️
const AuthPage: NextPage = () => {
const { data: session } = useSession();
const router = useRouter();
const { data: profile, error: profileError } = useSWR(['process.env.ENDPOINT_URL' + '/users/profile', session?.accessToken], fetcher);
useEffect(() => {
if (!profile) router.push('/auth/signup');
if (session && profile) router.push('/')
}, [session, profile, router]);
// ~~~
}
そこで以下のように getServerSideProps
でリダイレクトするようにする。またredirectの分岐を増やすのが面倒だったので、Cognitoページからのredirect先は /auth/signup
に変更している。
// 🙆♂️
const Signup: NextPage = () => {
return <SignupPage />;
};
export default Signup;
export const getServerSideProps: GetServerSideProps = async (context) => {
const session = await getSession(context);
if (!session) {
return {
props: {},
};
}
const profile = await fetchProfile(
process.env.ENDPOINT_URL + '/users/profile',
session.accessToken
);
// プロフィールがある場合は / へ
if (profile.status === 200) {
return {
redirect: {
permanent: false,
destination: '/',
},
};
}
return {
props: {},
};
};
なおnext-authを使用している場合、ここでprofileよりも先にsessionの有無を確認しないと情報漏えいする可能性があるので気をつける。( FYI )
以上まとめると全部SWRでとりあえず書くのではなく、リダイレクトなどHTMLが表示されてしまうとまずい場合のデータ取得はgetServerSideProps
、表示された後の取得はSWRでするように使い分けようねという方針を立てておくと迷わないで進められる話。