🦻

Next.jsのサイトにmicroCMSをAPI接続する

2021/07/01に公開

今回はこのようなサイト内のニュース欄をmicroCMSを用いて作ります。
デプロイはAWS amplifyでする前提です。

microCMSの設定

(1)プロジェクトを作る


個人開発レベルではHobbyで事足りるかと(検証中)。

(2)APIを作成


リスト形式を選択

(3)投稿したい項目を定義

APIで取得したデータをmapで出す

(1)API keyを.envに書き込む

.env.production
NEXT_PUBLIC_API_KEY=your key

keyはこちら

(2)nextがexport出来るようにする

next.config.js
module.exports = {
  env: {
    X_API_KEY: process.env.X_API_KEY,
  },
}

(3)pages/index

componentに書き込んでも、なぜかうまく動作しないので、直接pagesに書き込むことをお勧めします。

pages/index.tsx
import styles from '../styles/Home.module.scss'
import Link from 'next/link'
import React from 'react'
import Moment from 'react-moment'
import Icon from '../components/bases/IconCompo'

export const getStaticProps = async () => {
  const key = {
    headers: { 'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY },
  }
  const newsData = await fetch('apiURL', key)
    .then((res) => res.json())
    .catch(() => null)
  return {
    props: {
      news: newsData.contents,
    },
  }
}
const Home = ({ news }) => {
  return (
      <div className={styles.news}>
        <p className={styles.title}>ニュース</p>
        <div className={styles.newsContainer}>
          {news.slice(0, 4).map((news) => (
            <Link href={`news/${news.id}`} key={news.id}>
              <div className={styles.item}>
                <tr>
                  <td className={styles.date}>
                    <Moment format="YYYY/MM/DD" style={{ marginRight: 30, color: '#a1a1a1;' }}>
                      {news.date}
                    </Moment>
                  </td>
                  <td className={styles.body}>{news.title}</td>
                </tr>
              </div>
            </Link>
          ))}
        </div>
        <button className={styles.moreContainer}>
          <span>
            もっと見る
            <Icon type="arrowRight" />
          </span>
        </button>
    </div>
  )
}

export default Home

・apiURLはこのページから取得します

・Momentは、別記事で紹介してます。
・.slice(0,4)は、直近の1番目から4番目までだけを表示します。

(4)CSS

.news {
    text-align: center;
    padding-top: 2%;
    .title {
      font-size: 30px;
      font-weight: bold;
    }
    .newsContainer {
      width: 50%;
      margin: 0 auto;
      border-top: solid 1px #e8e8e8;
      .item {
        width: 100%;
        border-bottom: solid 1px #e8e8e8;
        tr {
          td {
            cursor: pointer;
            padding: 23px;
            font-weight: bold;
            text-align: left;
          }
        }
      }
    }
    .moreContainer {
      margin: 0 auto;
      padding: 20px 0;
      span {
        display: flex;
        justify-content: center;
        align-items: center;
        font-family: 'ten mincho text';
        font-size: 15px;
        font-weight: bold;
        color: #606060;
      }
    }

これで外観は完成したかと思います。

(4)詳細を表示するページを作る

ニュースのタイトルをクリックしたときに、その詳細を表示させるページを作ります。
pages/newsを作成

pages/news/index.tsx
import styles from './id.module.scss'
import Moment from 'react-moment'

export const getStaticPaths = async () => {
  const key = {
    headers: { 'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY },
  }
  const data = await fetch('https://examplerenren.microcms.io/api/v1/news', key)
    .then((res) => res.json())
    .catch((err) => console.warn(err))
  const paths = data.contents.map((content) => `/news/${content.id}`)
  return { paths, fallback: false }
}

export const getStaticProps = async (context) => {
  const id = context.params.id
  const key = {
    headers: { 'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY },
  }
  const data = await fetch('https://examplerenren.microcms.io/api/v1/news/' + id, key)
    .then((res) => res.json())
    .catch((err) => console.warn(err))
  return {
    props: {
      news: data,
    },
  }
}

const NewsId = ({ news }) => {
  return (
    <div>
          <div className={styles.contents}>
            <h1 className={styles.title}>{news.title}</h1>
            <Moment format="YYYY/MM/DD" className={styles.date}>
              {news.publishedAt}
            </Moment>
            <div className={styles.imgContainer}>
              <img src={news.thumbnail.url} className={styles.thumbnail}></img>
            </div>
            <div
              className={styles.body}
              dangerouslySetInnerHTML={{
                __html: `${news.body}`,
              }}
            />
          </div>
    </div>
  )
}
export default NewsId

これで表示できると思います。
getStaticPropsのところのapiのURLの最後に/を追加するのを忘れないでください。
1日ハマりました。

Discussion