【React】Next.jsを使ってみた

Next.jsで遊んでみた内容をメモしています。

getStaticProps

ビルド時に処理を行い、事前に静的なファイルを生成します。
ローカル起動時はアクセス毎に処理を行います。

export const getStaticProps: GetStaticProps = async () => {
  const response = await fetch('https://example.com/data')
  const data = await response.json()
  return {
    props: {
      data
    }
  }
}

getStaticPropsの結果がpropsに格納されます。
dataというプロパティに格納したので、props.dataでアクセスできます。

interface Props {
  data: InferGetStaticPropsType<typeof getStaticProps>
}

const App: React.FC<Props> = (props) => {
  // getStaticPropsの結果が表示されます
  console.log(props.data)
  return (
    <div></div>
  )
}

getStaticPaths+getStaticProps

公式によると、/post/[id].js のようにする事で、[id]に動的なパラメータを設定したURLを生成できます。
[id]の部分を取得するのが、getStaticPathsになります。

export const getStaticPaths: GetStaticPaths = async () => {
  const response = await fetch(`https://example.com/data`)
  const data = await response.json()

  const paths = data.map((x:any) => {
    return {
      params: {
        id: String(data.id),
      },
    }
  })

  return {
    paths: paths,
    fallback: false,
  }
}

getStaticPathsで取得した[id]を元に、事前に静的なファイルを生成します。

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const id = params.id
  const response = await fetch(`https://example.com/data/${id}`)
  const data = await response.json()
  return {
    props: {
      data
    }
  }
}

getStaticPropsの結果がpropsに格納されます。
dataというプロパティに格納したので、props.dataでアクセスできます。

const Posts: React.FC = (props: any) => {
  return (
    <div>
      {props.data.map((data) => <Post key={data.id} data={data} />)}
    </div>
  )
}

URLが/post/[id].js なので、postsというフォルダの中に [id].js を作成します。

import Link from "next/link";

interface Props {
  post: any;
}

const Post: React.FC<Props> = ({ data }) => {
  return (
    <div>
      <Link href={`/posts/${data.id}`}>
        <span>{data.text}</span>
      </Link>
    </div>
  );
}

export default Post;

fallback

getStaticPathsfallback: falseを指定しましたが、false以外にもtrueとblockingがあります。

  • false:ビルド時に静的ページが作成されなかった場合、その後に静的ページが追加されても404になります。
  • true:ビルド時に静的ページが作成されなかった場合、その後に静的ページが追加されるとアクセスできます。
  • blocking:fallback: trueとほぼ同じ動きですが、blockingはgetStaticPaths()が完了してから表示されます。

以下は公式ドキュメントのソースの一部です。
fallback: trueの場合、getStaticPaths()の非同期処理中はisFallbacktrueになります。
fallback: blockingの場合、isFallbackが使用できません。

function Post({ post }) {
  const router = useRouter()

  if (router.isFallback) {
    return <div>Loading...</div>
  }

  // Render post...
}

export async function getStaticPaths() {
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
  return {
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
    fallback: true,
  }
}

getStaticProps+Incremental Static Regeneration

getStaticPropsでビルド時に静的ファイルした後は更新されないのですが、revalidateを指定する事で再生成されるようになります。
この辺の動きはややこしくて、
1. データを更新する
2. Aさんがアクセスした際は古い内容が表示される
3. Aさんが参照した時点でファイル再生成処理が動く
4. Bさんがアクセスした際は新しいデータ(1.で更新したデータ)が表示される
という動きになるみたいです。
revalidate: 10とすると、最大で10秒に1回に再生成処理が動作します。

export const getStaticProps: GetStaticProps = async () => {
  const response = await fetch('https://example.com/data')
  const data = await response.json()
  return {
    props: {
      data,
    },
    revalidate: 10,
  }
}

useSWR

リアルタイムに画面を表示したい場合、SWRというhooksが便利です。
公式のソースコードを参考にすると、こんな感じになります。

const fetcher = (url: any) => fetch('https://example.com/data').then(response) => response.json());

const Posts: React.FC<Props> = ({ posts }) => {
  const { data } = useSWR('/api/posts', fetcher, { initialData: posts })
}

export const getStaticProps: GetStaticProps = async () => {
  const response = await fetch('https://example.com/data')
  const data = await response.json()
  return {
    props: {
      posts,
    },
    revalidate: 10,
  }
}

useSWRの戻り値にmutateというのがあり、ここがうまくまとまっていて分かりやすかったです。
mutateSWRが保持しているキャッシュを更新するためのものです。