初めに
今回はブログを開発するにあたり、今回初めて触る技術、Next.jsとChakraUIについて学んだことを簡単にまとめようと思います。
Next.jsのお勉強
基本的な内容をお勉強します。
SSGとSSRとISR
Nextjsに限らずですが、世の中には3種類のwebアプリの作り方があるようです。
詳しい内容は大量の他サイト様が既に記載されているので割愛しますが、簡単に言うと
SSG: StaticSiteGeneration
予め全ページをビルドしておいて、デプロイ後バックエンドと通信しない(jsでの非同期通信は除く)
LPなど静的ページの場合に選択する
SSR: ServerSideRendering
URLを叩かれて初めてバックエンドに問い合わせて、HTMLを返してもらう
DBに接続して画面のデータ数が動的に変わる場合に選択する。
ISR: IncrementalStaticRegeneration
基本的にはSSRだが、指定した時間ごとにキャッシュ作成し、キャッシュのデータを表示して裏でバックエンドに問い合わせ、キャッシュを更新する
パフォーマンス面ではSSGが一番だけど、データを取り扱うならSSRになる。
ただ、データ更新頻度が低い(リアルタイム性が重要視されない)場合は、ISRが選択肢に入る。
今回はブログなので、ISRで作れないか試してみました。
NextjsでのISRのやり方
Nextjsでは、pages
配下に置かれたtsx
ファイルがページとして認識されます。
その際、pages配下の相対パスがそのままページのuriになります。
とてもわかりやすい。
pages配下のコンポーネントでは、reactの通常のコンポーネントの他に
getStaticProps
getStaticPaths
getServerSideProps
の3つの特殊メソッドを使用できます。
それぞれ下記の用途で使用します。
getStaticProps
SSG / ISRのページで、ビルド時にバックエンド側で行う処理を記述できる。同時に、コンポーネントに渡す引数を戻り値として設定できる。ISRにする場合は、
revalidate
を戻り値のキーに加える。
getStaticPaths
[id].tsx
といった動的にファイル名が決定するコンポーネントで使用でき、自身が取りうるパスの配列を戻り値として返すことで、そのuriにアクセスした際に読み込まれるようになる。
getServerSideProps
SSRのページで使用できる。問い合わせがあった際にバックエンド側で行う処理を記載できる。コンポーネントに渡す引数を戻り値として設定できる。
また忘れてはならない特徴が、これらのメソッドはサーバーでのみ実行され、フロントにはメソッド自体が渡されません。
つまり、DBアクセスキーといったセキュアなものも記載できるといった特徴があります。
めちゃ便利...なんだけど、1ファイルでバックのみ対象の記述とフロントのみ対象の記述が混在するのは慣れるまで混乱しそう...。
今回はSSRは利用しないので、SSG / ISRで利用するgetStaticProps、getStaticPathsを使用します。
下記は記事一覧を取得するためのgetStaticPropsと、記事詳細で記載するgetStaticPathsです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// server側で呼ばれる
export const getStaticProps = async () => {
const token: string = process.env.NOTION_TOKEN;
const databaseId: string = process.env.NOTION_BLOG_DATABASE;
const notion = new Notion(token, databaseId);
const allPostsData = await notion.getPostList();
return {
props: {
allPostsData: allPostsData,
},
revalidate: 1 * 60
}
}
revalidate: x
と記載しておくと、
「最終レンダリングからx秒後以降にアクセスが有った場合に、キャッシュを返した後裏側でgetStaticPropsを呼び、キャッシュを更新する」
という動きになります。
上記の例では1分で設定しています。
getStaticProps
の戻り値はそのままコンポーネントの引数になります。
1
2
3
4
5
6
7
8
9
10
11
12
13
import { InferGetStaticPropsType } from 'next'
type Props = InferGetStaticPropsType<typeof getStaticProps>;
export default function Home({allPostsData}: Props){
return (
<Layout home>
<PostList
data = {allPostsData}
/>
</Layout>
)
}
InferGetStaticPropsType
はgetStaticProps
の戻り値の型を明示的に記載しなくても予測してくれる便利ものです。
[id].tsx
のようにパスも動的に決まる場合は、getStaticProps
に加えてgetStaticPaths
も同時に利用するようにします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// server側で呼ばれる
export const getStaticPaths: GetStaticPaths = async () => {
const token: string = process.env.NOTION_TOKEN;
const databaseId: string = process.env.NOTION_BLOG_DATABASE;
const notion = new Notion(token, databaseId);
const allPostsData = await notion.getPostList();
const pathList = allPostsData.map(post => {
return {
params: {id: post.slug}
}
});
return {
paths: pathList,
fallback: false
}
}
これらはサーバー側で呼ばれる処理なので、DBに直接アクセスするよう記載しても外に漏れません。
APIに渡さなくても良いのは楽ですね。
Next.jsの環境変数の扱いについて
API
Next.jsはpages/
配下にapi/
フォルダを用意することが出来て、その中にバックエンドのAPIを用意することができます。
パスは通常のpages/
と同様に、フォルダ構成がそのままuriとなります。
ChakraUIのお勉強
レスポンシブ対応はmedia queryを書かなくてもある程度制御できるようになってる
1
2
3
4
5
<Text
fontSize={{base: '12px', md: '14px', lg: '24px'}}
>
test text
</Text>
みたいにかくと、画面サイズに合わせてフォントサイズが変わる。素晴らしい。
ちなみに生でメディアクエリを制御するには、useBreakpointValue()
を利用する
1
2
3
4
5
6
7
8
import { useBreakpointValue } from '@chakra-ui/react'
export default () => {
const breakPoint = useBreakpointValue({ lg: 'desktop', sm: 'mobile' }, 'lg')
// lgサイズになるとbreakPoint = 'desktop'
// smサイズになるとbreakPoint = 'mobile' となる
// 第2引数は初期値。これがないとundefinedが初期値となり、画面がちらつく原因になる
}