🎉

Next.js入門

2022/04/15に公開

Next.jsはじめての環境構築備忘録
公式をメインにまとめ
編集中

実施環境
項目 詳細
PC MacBook Pro(14インチ、2021)Apple M1 Pro
OS MacOS Monterey 12.3
Node.js v16.14.2(インストール済み前提)
Next.js v12.1.5

Next.js 概要

オープンソースで提供されるReactベースのフロントエンドフレームワーク。
Reactでの開発に必要な機能(SSRやルーティングなど)をあらかじめ備えている。

Hello world

プロジェクトの生成

create next-appでプロジェクト生成可能。
--tsオプションでtypescript追加。(--typescriptでも可)
プロジェクト名を聞かれるので、好きな名前を設定。

プロジェクト生成
npx create-next-app@latest --ts
# or
yarn create next-app --ts

その後、下記でデフォルトページ表示可能。
デフォルトでは http://localhost:3000 でアクセス可能。

起動
cd プロジェクト名
yarn dev

CSSの選択肢

大きく下記があるらしい

  • Pure CSS
  • CSS Modules
  • CSS-in-js

Pure CSS

設定不要

Button.css
.button {
  background-color: green;
}
Button.tsx
import { VFC } from 'react';
import './Button.css';

type ButtonProps = {
  title: string;
};

export const Button: VFC<ButtonProps> = ({title}) => {
  return <button className="button">{title}</button>
};

ただ、componentsでimportしようとすると怒られる。

./src/components/partials/Button.css
Global CSS cannot be imported from files other than your Custom <App>. Due to the Global nature of stylesheets, and to avoid conflicts, Please move all first-party global CSS imports to pages/_app.js. Or convert the import to Component-Level CSS (CSS Modules).
Read more: https://nextjs.org/docs/messages/css-global
Location: src/components/partials/Button.tsx

_app.*tsxでimportするといける。
つまりグローバル管理になってしまうため、コンポーネントベースという思想とは合わなそう。

あとはtsxファイル内に書いてしまうか。
こちらの方がまだマシ。
だだしこれも推奨されないとのこと。

Button.tsx
import { VFC } from 'react';

type ButtonProps = {
  title: string;
};

const style = {
  backgroundColor: "green",
}

export const Button: VFC<ButtonProps> = ({title}) => {
  return <button style={style}>{title}</button>
};

つまりReactのプロジェクトで各ページのスタイリングに素のCSSを使うことはほとんどないと思われる。たぶん。(グローバルに当てたいスタイルは上記で記述する。reset cssとか。)

CSS Modules

Next.jsのビルドインサポート。

Button.module.css
.button {
  background-color: green;
}
Button.tsx
import { VFC } from 'react';
import style from './Button.module.css';

type ButtonProps = {
  title: string;
};

export const Button: VFC<ButtonProps> = ({title}) => {
  return <button className={style.button}>{title}</button>
};

古い技術で、css-loaderでdeprecatedになりそうらしい。
ただ今の所Next.jsビルドインサポートしているし、問題はなさそう。

CSS-in-JS

いくつか種類があり、styled-components, emotionあたりが有名。

試しにstyled-componentsを使ってみる。

インストール
yarn add styled-components
yarn add --dev @types/styled-components

書き方

Button.tsx
import { VFC } from 'react';
import styled from "styled-components"

type ButtonProps = {
  title: string;
};

export const Button: VFC<ButtonProps> = ({title}) => {
  const Button = styled.button`
    background-color: green;
  `

  return <Button>{title}</Button>
};

CSS modulesとの違い

  • tsxファイルとcssファイルを一つにまとめられる
  • テンプレートリテラルでの指定のため、動的に変更できる

CSS-in-JS良さそうと思うが、CSS ModulesがNext.jsのビルドインサポートなのはいろいろ理由があるらしい。

ページの追加

ルーティング

Next.jsでは、pagesフォルダ配下のディレクトリ構造がそのままページURLになる。

  • pages/index.js -> https://{あなたのドメイン}/
  • pages/posts/first-post.js -> https://{あなたのドメイン}/posts/first-post
  • pages/posts/[pageId].js -> https://{あなたのドメイン}/posts/{ページID}
    • これは動的なルーティングのケースでページIDによって出し分けるような場合に使う
    • 例えば、 https://{あなたのドメイン}/posts/a123 の場合、下記 pageId が a123 になる
/pages/posts/[pageId].js
import { useRouter } from 'next/router';

const Posts = () => {
  const router = useRouter();
  const { pageId } = router.query;

  return <p>Post: {pageId}</p>;
};

export default Post;

リンク

Next.jsではaタグの利用は非推奨で、Linkコンポーネントを使う。
Linkコンポーネントを使えば、クライアントサイドで遷移ができる。
aタグを使うと、毎回フロントサーバにリクエストを投げることになる。

※ただし外部リンクの場合はaタグを使用する

リンクコンポーネント
import Link from 'next/link'

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

動的なルーティングのケース

動的ルーティング
import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${encodeURIComponent(post.slug)}`}>
            <a>{post.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts

Linkコンポーネントの詳細はこちら

code splitting

Next.jsではあるページにアクセスした場合、そのページに必要なコードのみがロードされる。
それによってページの独立性が保たれ、速度も上がる。
ただし、そのページ上にLinkタグがある場合、その先のページのロードをバックグラウンドで行う。
そのため、ページ遷移自体はクライアント側で実施され、高速な遷移を実現できるらしい。(プロダクションビルド時のみ)

Assets

画像など

画像などは public フォルダ内に配置し、下記の様に使用

public/images/profile.jpgの画像
<img src="/images/profile.jpg" alt="Your Name" />

publicフォルダは robots.txtfavicon.ico などの配置にも適している。素のHTMLなんかをおいても大丈夫。詳細はこちら

Imageコンポーネント

Next.jsには画像関連をいろいろと最適化してくれるImageコンポーネントがある。

  • スクリーンサイズごとの最適化
  • WebPなどの最新フォーマットのサポート

などなど
詳細はこちら

Imageコンポーネント
import Image from 'next/image'

const YourComponent = () => (
  <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"
  />
)

参考

Discussion