MacでNext.jsのGettingStartedを進めてみる (2)

Macで [Next.jsの公式Getting Started](https://nextjs.org/docs/getting-started)を進めてみたメモ。

使用した環境は Intel Mac + Catalinaです。
バックエンドとしては[strapi](https://strapi.io/)を使っていきます。

[前回の記事で Getting Started の章をやりました。](https://qiita.com/tk_hamaguchi/items/5fde2017dc553f5a797e)
今回は Basic Features / Pages やっていきます。

# 2. Basic Features / Pages をやってみる

続いて[Basic Features / Pages](https://nextjs.org/docs/basic-features/pages)ページの内容をやってみます。

## 2.1. Static Generation without dataの例

Next.jsのSSG(静的サイト生成)について触れられているところで about ページを作るところがあったので作ってみる。
こちらもTypeScriptで作成する。

1. `pages/about.tsx`を下記の内容で作成する

    ```tsx:pages/about.tsx
    function About() {
      return <div>About</div>;
    }
    
    export default About;
    ```

2. ブラウザで作成したページを開いてみる

    ```sh:command
    $ open http://localhost:3000/about
    ```
    ![スクリーンショット 2021-05-23 17.16.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/f566fe33-baf7-25c6-1bd4-c11b2977d66a.png)


## [ちょっと寄り道] バックエンドAPIの作成

次のセクションでバックエンドのCMSがあった方が良さそうなので、[strapi](https://strapi.io/)でサクッと建てる。

1. strapi用にターミナルを別で起動して、作業用のフォルダに移動する

    ```sh:command
    cd ~/devel/
    ```

2. strapiのプロジェクトを作成する

    ```sh:command
    $ yarn create strapi-app --quickstart next-sample-backend
    ```
    ```plaintext:output
    yarn create v1.22.10
    [1/4] 🔍  Resolving packages...
    [2/4] 🚚  Fetching packages...
    [3/4] 🔗  Linking dependencies...
    [4/4] 🔨  Building fresh packages...
    
    ~~~~~~~~ 中略 ~~~~~~~~
    
    One more thing...
    Create your first administrator 💻 by going to the administration panel at:
    
    ┌─────────────────────────────┐
    │ http://localhost:1337/admin │
    └─────────────────────────────┘
    ```

3. ブラウザが開くので必要な情報を入力する（ブラウザが機能しない場合は http://localhost:1337/admin にアクセスする）
   ![スクリーンショット 2021-05-23 18.11.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/4276ddc1-8937-1497-71a8-af4530331f3e.png)

4. strapiの管理画面が開くので、［Content-Type Builder］→［Create new collection type］を選択する
    ![スクリーンショット 2021-05-23 18.12.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/03c3d844-1f13-ffb1-d912-de25ef30b385.png)

5. ［Display name］に `Post` と入力し、［続ける］をクリックする
    ![スクリーンショット 2021-05-23 18.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/8e8977b7-7a22-382f-f6d0-9dcd7c1a2c88.png)

6. とりあえず`title`があれば良いようなので、［Text］をクリックする
    ![スクリーンショット 2021-05-23 18.12.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/7d17fef1-d699-8d52-cb69-a68e3e26cb8f.png)

7. ［Name］に `title` と入力し、 ［終了］をクリックする
    ![スクリーンショット 2021-05-23 18.12.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/dba26fff-b5ff-e158-d13b-a9148ea2b748.png)

8. Postとして作成する内容が表示されているので、問題なければ（ないと思うけど）［保存］をクリックする
    ![スクリーンショット 2021-05-23 18.12.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/fca70369-413b-149b-fa09-8630ec78f40e.png)

9. strapiがリスタートするまで待つ
    ![スクリーンショット 2021-05-23 18.12.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/d3623689-974c-6220-f8f3-3fcb3f3354dd.png)

10. 次に `/posts` のエンドポイントを公開する設定をするため、［設定］→［ロールと権限］を開いて、［Public］の行をクリックする
    ![スクリーンショット 2021-05-23 18.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/623f9158-f126-3ba7-59bd-f0cab6de040d.png)

11. Publicの設定が表示されるので、［権限］エリアの［find］と［findone］にチェックを入れる
    ![スクリーンショット 2021-05-23 18.13.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/7512b998-661e-b6e0-b86e-9c75d34c8398.png)

12. 続いてデータを投入する。［コレクションタイプ］→［Posts］をクリックし、［Postsを追加］ボタンをクリックする
    ![スクリーンショット 2021-05-23 18.13.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/a9c6f284-c8c0-3e19-738c-60b3c903c9eb.png)

13. ［Title］に適当な文字（例の場合は`ほげ`）を入力し、［保存］をクリックする
    ![スクリーンショット 2021-05-23 18.13.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/359ddbbe-f46e-5c80-2814-fe5d6f2109f9.png)

14. 保存されたデータを公開するために［Publish］をクリックする
    ![スクリーンショット 2021-05-23 18.13.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/5b127c96-2725-166c-6bc7-923944d84940.png)

15. ［Published］が表示されれば作成できた
    ![スクリーンショット 2021-05-23 18.13.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/c63ca79c-e58c-edd5-5e2e-33be8baccec5.png)

16. ［Posts］をクリックして一覧画面に戻り、同様にデータを何件か追加する（例では`ふが`をtitleに持つデータを追加
    ![スクリーンショット 2021-05-23 18.14.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/b584f7fe-24b1-ca21-1913-b949d0aee287.png)

17. これで http://localhost:1337/posts にアクセスしたときに適当にタイトルが返るAPIが作成できた

    ```sh:command
    $ curl http://localhost:1337/posts
    ```
    ```json:output(整形済)
    [
      {
        "id": 1,
        "title": "ほげ",
        "published_at": "2021-05-23T09:13:53.895Z",
        "created_at": "2021-05-23T09:13:47.938Z",
        "updated_at": "2021-05-23T09:13:53.906Z"
      },
      {
        "id": 2,
        "title": "ふが",
        "published_at": "2021-05-23T09:14:09.970Z",
        "created_at": "2021-05-23T09:14:08.718Z",
        "updated_at": "2021-05-23T09:14:09.980Z"
      }
    ]
    ```

このままstrapiは起動したままにして

## 2.2. Static Generation with dataの例

### 2.2.1. シナリオ１ getStaticPropsを使う例

1. 下記の内容で `pages/blog.tsx` を作成する
    * 公式にファイル名の記載がなかったので適当
    * 型は暫定的に `any`を設定

    ```tsx:pages/blog.tsx
    function Blog({ posts }: {posts: any}) {
      return (
        <ul>
          {posts.map((post: any) => (
            <li>{post.title}</li>
          ))}
        </ul>
      );
    }

    // This function gets called at build time
    export async function getStaticProps() {
      // Call an external API endpoint to get posts
      const res = await fetch("http://localhost:1337/posts");
      const posts = await res.json();

      // By returning { props: { posts } }, the Blog component
      // will receive `posts` as a prop at build time
      return {
        props: {
          posts,
        },
      };
    }

    export default Blog;
    ```

2. ブラウザで開いてみる

    ```sh:command
    $ open http://localhost:3000/blog
    ```
    ![スクリーンショット 2021-05-23 20.39.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/4b885a9c-8812-cb73-3647-53e969c7b9da.png)


先ほどstrapiで登録したPostのtitleが表示された。


### 2.2.2. シナリオ２ getStaticPathsを使う例

1. 下記の内容で `pages/posts/[id].tsx` を作成する
    * 型は暫定的に `any`を設定

    ```tsx:pages/posts/[id].tsx
    function Post({ post }: {post: any}) {
      // Render post...
      return <h1>[{post.id}] {post.title}</h1>;
    }

    // This function gets called at build time
    export async function getStaticPaths() {
      // Call an external API endpoint to get posts
      const res = await fetch("http://localhost:1337/posts");
      const posts = await res.json();

      // Get the paths we want to pre-render based on posts
      const paths = posts.map((post: any) => ({
        params: { id: String(post.id) },
      }));

      // We'll pre-render only these paths at build time.
      // { fallback: false } means other routes should 404.
      return { paths, fallback: false };
    }

    // This also gets called at build time
    export async function getStaticProps({ params }: {params: any}) {
      // params contains the post `id`.
      // If the route is like /posts/1, then params.id is 1
      const res = await fetch(`http://localhost:1337/posts/${params.id}`);
      const post = await res.json();

      // Pass post data to the page via props
      return { props: { post } };
    }

    export default Post;
    ```
    * `Render post...` のところは適当にタグを生成
    * `getStaticPaths` の params は Stringでないとエラーが出るので、公式では `params: { id: post.id },` だったところを `params: { id: String(post.id) },` に修正

2. ブラウザで開いてみる

    ```sh:command
    $ open http://localhost:3000/posts/1
    ```
    ![スクリーンショット 2021-05-23 21.12.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164813/bf9ee343-b174-df25-4093-0db8c3d18a82.png)

先ほどstrapiで登録したPostのid=1のtitleが表示されました。

次回は Basic Features / Data Fetching を進めていきます。

# MacでNext.jsのGettingStartedを進めてみる シリーズの記事

1. [Getting Started をやった記事](https://qiita.com/tk_hamaguchi/items/5fde2017dc553f5a797e)
2. Basic Features / Pages をやった記事
3. [Basic Features / Data Fetching をやった記事](https://qiita.com/tk_hamaguchi/items/9fb3c74833206319609d)