NEXT.JSチュートリアル

9 min読了の目安(約8100字TECH技術記事

はじめに

自分のメモように書いています。

ページ作成

  • pages/の配下で作成されたファイルがページとして表示される
  • ファイルのルートがそのままリンクのパスになる
  • Routeを設定しなくて良い
pages/posts/first-post.js
export default function FirstPost() {
  return <h1>First Post</h1>
}

Linkコンポーネント

import Link from 'next/link'
pages/index.js
<h1 className="title">
  Read{' '}
  <Link href="/posts/first-post">
    <a>this page!</a>
  </Link>
</h1>
pages/posts/first-post.js
import Link from 'next/link'

export default function FirstPost() {
  return (
    <>
      <h1>First Post</h1>
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </>
  )
}
  • <Link href="">で繋がれたページはprefetchされる
  • アプリ内リンク遷移はaタグでも囲む
    → <Link href=""><a></a></Link>
    ※ アプリ外のページはLink コンポーネントの中に<a>は使わない
  • 属性をつけるときは<a>タグに追加する
    書き方

prefetch: Linkコンポーネントで繋がれたリンク先は事前にサーバー側で読み込まれている
→表示が高速化される

Asset

静的ファイル(txt、 画像など)

• Publicディレクトリの中で静的ファイルを参照する
• Publicをルートとしたルートパスで記述

静的ファイルのパス

<img src="/〇〇.svg" alt="Vercel Logo" className="logo" />
	
imgディレクトリを作った場合
<img src="/img/〇〇.svg" alt="Vercel Logo" className="logo" />

Imageコンポーネント

インポートすることで利用可能になる
import Image from 'next/image'

画像の最適化

  • デバイスに応じて画像サイズを自動で変更
  • pngやjpegなどの形式を画像を自動でwebP
  • 画像にwidthとheightを指定しても、レスポンシブ対応してくれる(アスペクト比が崩れない)
  • ロードに対応(loading=lazy)

以下の記事を参考にさせていただきました。よくまとまっているので読んでみてください。
Next.jsのnext/imageコンポーネントの使い方と注意点

<Image
  src="/images/profile.jpg" // Route of the image file
  height={144} // Desired size with correct aspect ratio
  width={144} // Desired size with correct aspect ratio
  alt="Your Name"
/>	

Headコンポーネント

  • Headコンポーネントをimportする
  • Headコンポーネントは<head>タグに変換される
  • ページごとに設定できる SEO的に良い
    <link href=“”>  CSSやCDNを読み込む
import Head from 'next/head'
<Head>
  <title>Create Next App</title>
  <link rel="icon" href="/favicon.ico" />
</Head>

Headコンポーネントのリファレンス->https://nextjs.org/docs/api-reference/next/head
pages/_document.jsでhtmlの属性をカスタマイズできる
カスタムドキュメント

CSSスタイリング

  • CSSとSassが組み込まれている
  • styled-jsが組み込まれている
  • style-components,emotionなどのライブラリも使用可能
  • TailWindCSSの使用も可能

レイアウトコンポーネント

components/layout.js
export default function Layout({ children }) {
  return <div>{children}</div>
}
pages/posts/first-post.js
import Head from 'next/head'
import Link from 'next/link'
import Layout from '../../components/layout'

export default function FirstPost() {
  return (
    <Layout>
      <Head>
        <title>First Post</title>
      </Head>
      <h1>First Post</h1>
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </Layout>
  )
}

スタイルをCSS Moddulesで記述

components/layout.module.css
.container {
  max-width: 36rem;
  padding: 0 1rem;
  margin: 3rem auto 6rem;
}

CSS Modulesの特徴
 • コンポーネント内で同じクラス名がなければ、ユニーク名クラス名を作成してくれる
 • コンポーネント別でスタイルを変えたい時には便利
 • Layoutコンポーネントでラップする
 • CSS Modulesを使用するときは、CSSのファイル名の末尾に.module.cssをつける

components/layout.js
スタイルを追加
import styles from './layout.module.css'

export default function Layout({ children }) {
  return <div className={styles.container}>{children}</div>
}

global style

pages/_app.jsにglobal CSSの追加が可能、他の場所からのインポートは不可能

_app.jsについて

  • _app.jsは特殊なファイルでRouteコンポーネントをラップ
  • 全ページで共通して実行させたいファイルを読み込む
  • 全ぺージで共通して実行させたい処理を実行する
    → 認証のリッスン Authなど
  • 全ページで共通のレイアウトを組み込む
pages/_app.js
export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

pages/_app.jsを追加した時はサーバーを再起動します

pages/_app.js
import '../styles/global.css'

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

Pre-rendering

  • デフォルトで全てのページをpre-render

  • pre-render = 事前にHTMLを生成すること
    →通常ブラウザがHTMLを読み込んでから表示される
    事前に別の場所で読み込ませる。ユーザーがアクセスする前に読み込み

  • 通常のReactアプリだとブラウザのjsの読み込みを無効化するとアプリが表示されない
    → ブラウザがjsを読み込んでHTMLを生成するため

  • ブラウザの負荷を下げて、表示を高速化
    → サーバーが事前に読み込んでくれる

  • 検索エンジンのクローラーにコンテンツを見せられる
    → 事前にレンダリングされてページが見つからないということが起きないため
    通常だとブラウザが読み込んでいる最中にクローラーがコンテンツがないと判断してSEOがマイナス評価になる

renderingの種類

ひとつのアプリの中で使い分けが可能

1.Static Generation

→ ビルドされたらHTMLが事前に生成
 ユーザーは皆同じページを見ることになる

表示が高速 更新頻度が低い ユーザー:コンテンツ = 1:N
例 ブログ ECサイト LP 問い合わせ

2.Server-side Rendering

→ ユーザーがアクセスされた時にサーバー側でHTMLを生成
ユーザーがアクセスしたタイミングによっては、更新されている可能性がある
最新の状態でユーザがページを見れる

表示は遅くなる 更新頻度が高い ユーザー:コンテンツ = N:N
例 SNS チャット 動画配信 リアルタイム

3.Client-side rendering

→ ユーザーがアクセスした時ブラウザが読み込む
SEOを重要としないページ
例 管理画面 サービスサイト

静的ジェネレーション

  • データの有無にかかわらず実行可能

  • 外部データなし
    → ビルド時にHTMLをレンダリング

  • 外部データあり
    → 1. ビルド時にDBや外部APIからデータを取得
    2. 取得したデータを使ってHTMLをレンダリング
      getStaticProos()を使う

getStaticProps

• 外部データを取得するために使う
• async/awaitを使って非同期処理を制御が可能
• 本番環境ではビルド時に実行される
• 開発環境ではリクエスト毎に実行される(npm run dev)
• pageコンポーネントでのみ使用可能

export default function Home(props) { ... }

export async function getStaticProps() {
  // Get external data from the file system, API, DB, etc.
  const data = ...

  // The value of the `props` key will be
  //  passed to the `Home` component
  return {
    props: ...
  }
}

外部データをfetchする時

export async function getSortedPostsData() {
  // Instead of the file system,
  // fetch post data from an external API endpoint
  const res = await fetch('..')
  return res.json()
}

クエリの取得

import someDatabaseSDK from 'someDatabaseSDK'

const databaseClient = someDatabaseSDK.createClient(...)

export async function getSortedPostsData() {
  // Instead of the file system,
  // fetch post data from a database
  return databaseClient.query('SELECT posts...')
}

getServerSideProps

• リクエスト毎に実行される関数
• ServerーSide Renderingのために使う
• 外部データを取得するために使う
• Async/awaitを使って非同期処理を制御できる
• pageコンポーネントでのみ使用可能

export async function getServerSideProps(context) {
  return {
    props: {
      // props for your component
    }
  }
}

SWR

• Next.jsで用意されているSWRというHooks
• Client-sideでデータを取得するなら使用を推奨
• 取得したデータを{key: value}(オブジェクト)の形でキャッシュできる
• Real-timeでデータ更新(データの再fetch)
→ 戻るを押してもデータをフェッチして最新の状態に更新
• JAMstack指向
→ 開発手法

import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetch)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}	

Dynamic Routes

• ファイル名に[]を使うとDynamicRoutesになる
• idによってルーティングを変える
 pages/posts/[id].js

ex. URL → https://example.com/posts/[pre-rendering]

https://example.com/posts/[ssg-ssr]

getStaticPaths

• Idが動的に変更する部分を作成する時に使用
• pathsとfallbackを返す
• Pathsは事前ビルドするパス対象を指定するパラメータ
• Fallbackは事前ビルドしたパス以外にアクセスした時の動作

import { getAllPostIds } from '../../lib/posts'

export async function getStaticPaths() {
  const paths = getAllPostIds()
// オブジェクト型で返す
  return {
    paths,
    fallback: false → trueなら事前に用意した404のサイトを見せる
  }
}

https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data

Catch-all Routes

  1. pages/posts/[…id].jsにファイル名を変更
  2. getStaticPaths()で返すidを["a", "b","c"]のような配列に変更
  3. posts/a, posts/a/b, posts/a/b/c を作成する
return [
  {
    params: {
      // Statically Generates /posts/a/b/c
      id: ['a', 'b', 'c']
    }
  }
  //...
]
export async function getStaticProps({ params }) {
  // params.id will be like ['a', 'b', 'c']
}

API ルート

  • APIエンドポイントが作成可能
  • プレビューモードで利用される
  • クライアントでバンドルされない
  • getStaticPropsとgetStaticPaths内でAPIは叩かない

※プレビューモードとは
static generationを利用する際、ビルド時の反映ではなく
リクエスト時にデータのフェッチを反映させるための機能

pages/api/〇〇.js
// req = HTTP incoming message, res = HTTP server response
export default function handler(req, res) {
  // ...
}

APIルートで動的ページの作成方法(Dynamic API Route)
→ https://nextjs.org/docs/api-routes/dynamic-api-routes

Vercelでデプロイ

→ https://nextjs.org/learn/basics/deploying-nextjs-app/deploy
Gatsbyサイトを無料サーバーVercelで公開する方法を徹底解説

学習の際は以下のYouTubeを参考にさせていたただきました。
とてもわかりやすく解説されているのでおすすめです。

トラハックのエンジニア学習講座 日本一わかりやすいNext.js入門