レンダリング
今回はこちら(Pre-rendering and Data Fetching)を進めていきます。
Webアプリケーションにおいて画面の描画にはいくつかパターンがあります。以下で分かりやすく解説くださっています。特に2つ目の解説では昔から(今でも)よく使われているSST(JSP, Thymeleaf…etc)から技術の変遷を解説しているので分かりやすいです。
若干脱線しましたが、NextjsではSSR、SSG、ISRをサポートしています。
データ取得
チュートリアルではSSGでレンダリングする際にgetStaticPropsメソッドでブログ記事のデータを取得、画面にプロパティとして渡すことで取得データを画面に埋め込んで表示しています。
自分の場合は自作のAWS Lambdaを叩きDynamoDBに格納しているVtuber情報を取得、表示させます。libフォルダ配下に以下のapi.get.vtuber-info.ts
を作成しました。
型の生成はJSONから型情報を生成してくれるquicktypeを使用しています。
import config from './api.config.json';
import axios, { AxiosResponse } from 'axios';
import { VtuberInfo } from './type/vtuberInfo';
import apiResponse from './type/api.resposne.get.vtuber-info-list.json';
type ApiResponse = typeof apiResponse;
const API_SUCCESS: number = 200;
export const getVtuberInfoList = async () => {
const url = config.aws.dev.endpoint + config.aws.dev.apiname.getAllVtuberInfo;
/** 開始ログ */
console.log(`Start GET`);
/** Vtuberの一覧を取得 */
const response: AxiosResponse<ApiResponse> = await axios.get<ApiResponse>(
url
);
const { data, status } = response;
console.log('status: ' + status);
/** 取得できなかった場合は空のリストを返却 */
if (!data || status !== API_SUCCESS) {
console.log('Can`t get data ');
return [];
}
/** 終了ログ */
console.log(`End GET`);
/** 型名をつけて返却 */
const vtuberInfoLiat: VtuberInfo[] = data.vtuberInfoList.Items;
return vtuberInfoLiat;
};
画面側では上記のメソッドを使ってgetStaticProps
でデータを取得しpropsに設定しています。propsと合わせて設定しているrevalidateについては後ほど説明します。
取得した情報を使って箇条書きで並べて画面に表示しています。
スタイリング何もしていないですがこの辺りは別枠でTailwind CSSを適用して画面を作りこんでいきます。
普段レガシーな業務システムばかり触っているのでスタイリングはCSS普通に書くかBootstrap(or社内独自拡張テーマ) を使うことが多く、せっかくなのでTailwind CSSで画面を作りこんでいきたいです。
CSS in JSも選択肢にありますがこっちは個人的に多少書いたことがあったりせっかくNextjs使ってるので賛否両論のTailwind CSS使って感触を確かめたいところです。
import type { InferGetStaticPropsType, NextPage } from 'next';
import Link from 'next/link';
import { getVtuberInfoList } from '../../lib/api.get.vtuber-info';
import PageLayout from '../../src/components/pageLayout';
import Image from 'next/image';
import { URL_YOUTUBE_CHANNEL } from '../../src/app.const';
type Props = InferGetStaticPropsType<typeof getStaticProps>;
export const getStaticProps = async () => {
let vtuberInfoList = await getVtuberInfoList();
vtuberInfoList = vtuberInfoList.sort((a, b) => Number(a.vtuberId) - Number(b.vtuberId));
return {
props: {
vtuberInfoList
},
/** キャッシュ秒数(ISR) */
revalidate: 30,
};
}
const vtuberInfoListPage: NextPage<Props> = ({ vtuberInfoList }) => {
return (
<PageLayout>
<h1 className="title">Vtuber List</h1>
<h2>
<Link href="/">
<a>Go Home Page</a>
</Link>
</h2>
<ul>
{
vtuberInfoList.map((v) => {
return (
<li id={v.vtuberId} key={v.vtuberId}>
{v.youtubeInfo.title}
<br />
<Image
priority
src={v.youtubeInfo.icon}
height={50}
width={50}
alt={v.youtubeInfo.title}
/>
<Link href={ URL_YOUTUBE_CHANNEL + v.youtubeInfo.channelId}>
<a>YouTube</a>
</Link>
<Link href={v.twitterInfo.url}>
<a>Twitter</a>
</Link>
</li>
);})
}
</ul>
</PageLayout>
);
};
export default vtuberInfoListPage;
最後にrevalidateについてですが、冒頭で書いた通りNextjsではSSR、SSG、ISRをサポートしていますが、これはページごとに設定が可能です(ビルド時に自動で判別してくれる)。基本的にSSRを使用し、ページの中でgetStaticPropsを使用していればSSG、さらにgetStaticPropsの中でrevalidateを設定しているとISRのページになります。
ISRはrevalidateに設定した秒数だけキャッシュしたページを返却し、設定時間が経過した後の初回リクエストでページが再生成されます。(初回リクエスト時にはキャッシュを返したうえでページを再生するので更新後のページが見られるのは2回目以降のリクエストになります。)
一瞬勘違いしていたポイントとしては、ローカルで確認する際にnext dev
ではなくnext build
&next start
で実行しないとISRのキャッシュが効かなかったです。
今回は以上です。