NextJS13でレスポンシブデザインのフロントエンド画面を開発する方法まとめ


 

こんにちは。Tomoyuki(@tomoyuki65)です。

NextJS13にアップデートされて全く別物のフレームワークへ変わった感じですが、ようやく触る時間ができたので色々と試してみました。

合わせてレスポンシブデザイン(PCとスマホなど、画面のサイズで表示を変えるデザイン)のフロントエンド画面を開発する方法もまとめますので、よければぜひ参考にしてみて下さい。

 



NextJS13でレスポンシブデザインのフロントエンド画面を開発する方法まとめ

まずNextJS13でフロントエンド開発をするためには、事前にNodeのインストールなどの準備が必要になるため、まだの方は先にそちらの準備をして下さい。

今回使用するNodeのバージョンに関しては、本番環境へのデプロイ先としてAWS Amplifyを使うことを前提とするため、2023年9月時点で対応している最も新しいバージョン『18.13.0』を使うことにします。

Nodeの準備が完了したら以下のコマンドを実行し、NextJS13のプロジェクトを作成します。

$ mkdir next13dev
$ cd next13dev
$ npx create-next-app@latest

 

コマンド実行後、プロジェクトの設定について聞かれるので、プロジェクト名は「next13sample」、それ以外は全て「Yes」を選択し、最後にSuccess!が表示されればOKです。

 

これでプロジェクトが作成されたので、以下のコマンドを実行しディレクトリを移動します。

$ cd next13sample

 

作成されたプロジェクトをテキストエディタで確認し、次のようになっていればOKです。

※言語は「TypeScript」、CSSは「Tailwind.css」がすぐ使えるようになってます。

 

次にNodeのバージョンを固定しておきたいので、package.jsonにenginesの項目でnodeのバージョンを記述します。

・・
  },
  "engines": {
    "node": "18.13.0"
  }
}

 

そして以下のコマンドを実行し、ファイル「.npmrc」を作成後、ファイルの中には「engine-strict=true」を記述します。

$ touch .npmrc

 

engine-strict=true

 

これでNodeのバージョンを固定する設定が完了です。

では以下のコマンドを実行し、開発サーバーを起動します。

$ npm run dev

 

ブラウザで「http://localhost:3000/」にアクセスし、以下のような初期画面が表示されればOKです。

 

これでNextJS13の開発環境の構築が完了です。

ではまず手始めに画面に「Hello, world!」を表示させてみます。「src/app/page.tsx」のファイルの中身を全て削除し、以下の内容に変更します。

export default function Home() {
  return (
    <main>
      Hello, world!
    </main>
  )
}

 

ブラウザで「http://localhost:3000/」を確認し、以下のようになればOKですが、何やらCSSが反映されてしまっているので、次はこれを修正します。

 

これは「src/app/globals.css」のbodyタグに関するCSS設定が反映されているため、その部分をコメントアウトするか削除します。

 

もう一度ブラウザで「http://localhost:3000/」を確認し、以下のようになればOKです。

 



レスポンシブデザインのヘッダーを作成する

次にレスポンシブデザインのヘッダーを作成してみます。

以下のコマンドを実行し、コンポーネント格納用のディレクトリ配下に、共通コンポーネントとして「Header.tsx」を作成して格納します。

$ cd src
$ mkdir components
$ cd components
$ mkdir common
$ touch Header.tsx

 

次に「Header.tsx」の中身を次のようにします。

※ダグの範囲を確認しやすくするため、Tailwind CSSのクラス「bg-xx-yy」を使用し、背景色を付けて色分けしています。

export default function Header() {
  return (
    <header className="w-full sticky top-0 bg-gray-100">
      <nav className="p-1 bg-gray-200">
        <div className="hidden md:flex justify-between min-w-3xl bg-gray-300">
          <div className="ml-1 text-xl font-bold">
            Logo
          </div>
          <div>
            <ul className="flex">
              <li className="mx-2">
                Content1
              </li>
              <li className="mx-2">
                Content2
              </li>
              <li className="mx-2">
                Signup
              </li>
              <li className="mx-2">
                Login
              </li>
            </ul>
          </div>
        </div>
        <div className="md:hidden flex justify-between max-w-3xl bg-blue-200">
          <div className="text-xl font-bold">
            Logo
          </div>
          <div className="text-xl font-bold">
            三
          </div>
        </div>
      </nav>
    </header>
  )
}

※Tailwind CSSの大きさ「md(768px)」をブレークポイントとし、画面サイズがmdより小さい場合はタブレットやスマホ画面用の表示に切り替えるため、CSSのクラスに「hidden md:flex justify-between min-w-3xl」と「md:hidden flex justify-between max-w-3xl」を使用して表示させる内容を分けています。

 

次に共通レイアウトファイル「src/app/layout.tsx」を以下のように修正し、作成したヘッダーを表示させます。

import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import Header from '@/components/common/Header'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Header />
        {children}
      </body>
    </html>
  )
}

 

ブラウザで「http://localhost:3000/」を確認し、画面サイズが設定したブレークポイント(今回の例では768px)以上の時は次のように表示されます。

 

次にブラウザの横幅を小さくしていき、設定したブレークポイント(今回の例では768px)以下になったら次のように表示されればOKです。

 

このようにTailwind CSSで適切なブレークポイントを上手く設定すると、レスポンシブデザインに対応することが可能です。

 

タブレットやスマホ向けにバーガーメニューを作成する

上記で作成したヘッダーについては、ブレークポイント以下の表示で漢字の「三」を表示させていますが、実際はバーガーメニューを表示させる必要があるため、次はバーガーメニューを作成します。

そんなバーガーメニューの作成方法は色々ありますが、今回はパッケージ「react-burger-menu」を利用して作成する方法をご紹介します。

まずは以下のコマンドを実行し、パッケージ「react-burger-menu」をインストールします。

npm i react-burger-menu
npm i @types/react-burger-menu

 

次に以下のコマンドを実行し、ディレクトリ「src/components/common」配下にバーガーメニューコンポーネント「BurgerMenu.tsx」を作成します。

$ touch BurgerMenu.tsx

 

次に「BurgerMenu.tsx」の中身の例としては次のように記述します。

'use client'
import { useState } from 'react';
import { slide as Menu, State } from 'react-burger-menu'

// Menuコンポーネントに適用させるCSS
const styles = {
  bmBurgerButton: {
    position: 'fixed',
    width: '32px',
    height: '26px',
    right: '20px',
    top: '5px',
  },
  bmBurgerBars: {
    background: 'black'
  },
  bmCross: {
    background: 'white'
  },
  bmMenuWrap: {
    position: 'fixed',
    height: '100%',
    top: "0",
  },
  bmMenu: {
    background: 'dimgray',
    padding: '2.5em 1.5em 0',
  },
  bmItemList: {
    color: 'white',
  },
}

export default function BurgerMenu() {
  // メニュー画面の開閉状態を管理する「isMenuOpen」を設定
  const [isMenuOpen, setIsMenuOpen] = useState(false)

  // メニューを閉じるための関数を設定
  const handleCloseMenu = () => {
    setIsMenuOpen(false)
  }

  // メニュー画面の開閉状態を確認するための関数を設定
  const handleStateChange = (state: State) => {
    setIsMenuOpen(state.isOpen)
  }

  return (
    <div id="outer-container">
      <Menu
        isOpen={isMenuOpen}
        onStateChange={handleStateChange}
        pageWrapId={'page-wrap'}
        outerContainerId={'outer-container'}
        right={true}
        styles={styles}
      >
        <main id="page-wrap">
          <ul className="flex flex-col">
            <li className="mb-4">
              <button className="hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                Content1
              </button>
            </li>
            <li className="mb-4">
              <button className="hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                Content2
              </button>
            </li>
            <li className="mb-4 flex justify-center">
              <button className="mt-4 p-2 w-3/4 text-3xl border-2 rounded-lg bg-red-500 hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                Signup
              </button>
            </li>
            <li className="mb-4 flex justify-center">
              <button className="mt-4 p-1 w-3/5 border-2 rounded-lg bg-slate-400 hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                Login
              </button>
            </li>
          </ul>
        </main>
      </Menu>
    </div>
  )
}

※useStateを使ってバーガーメニューの開閉状態を管理し、ボタンをクリックした時にメニューが閉じるように設定しています。尚、NextJS13からはデフォルトがサーバーサイドコンポーネントであり、そのままだとuse〜系のコンポーネントは使えません。使いたい場合は一番最初に「use client」を記述し、クライアントコンポーネントに変えて下さい。

 

次に作成したバーガーコンポーネントを表示させるため、ヘッダーコンポーネント「Header.tsx」を次のように修正します。

import BurgerMenu from '@/components/common/BurgerMenu';

export default function Header() {
  return (
    <header className="w-full sticky top-0 bg-gray-100">
      <nav className="p-1 bg-gray-200">
        <div className="hidden md:flex justify-between min-w-3xl bg-gray-300">
          <div className="ml-1 text-xl font-bold">
            Logo
          </div>
          <div>
            <ul className="flex">
              <li className="mx-2">
                Content1
              </li>
              <li className="mx-2">
                Content2
              </li>
              <li className="mx-2">
                Signup
              </li>
              <li className="mx-2">
                Login
              </li>
            </ul>
          </div>
        </div>
        <div className="md:hidden flex justify-between max-w-3xl bg-blue-200">
          <div className="text-xl font-bold">
            Logo
          </div>
          <div className="text-xl font-bold">
            <BurgerMenu />
          </div>
        </div>
      </nav>
    </header>
  )
}

 

ブラウザで「http://localhost:3000/」を確認すると、次のようにバーガーメニューのボタンが表示されます。

 

バーガーメニューのボタンをクリックするとメニュー画面が開き、次のように表示されればOKです。(右上の×ボタンか、各種ボタンをクリックすると、メニューが閉じるようになってます。)

 



フッターの追加

次はフッターの追加を行います。以下のコマンドを実行し、ファイルを作成します。

$ touch Footer.tsx

 

「Footer.tsx」の中身の例としては次のように記述します。

import NextLink from "next/link";

export default function Footer() {
  return (
    <footer className="w-full bg-gray-100">
      <div className="p-1 bg-gray-200">
        <div className="flex flex-col">
          <div className="m-2 p-1 bg-blue-200">
            <p className="ml-2">
              | NextJS13 Sample
            </p>
            <ul className="flex ml-6 text-sm">
              <li className="mx-1 hover:opacity-50">
                <NextLink href="/">Home</NextLink>
              </li>
              <li className="mx-1">
                |
              </li>
              <li className="mx-1 hover:opacity-50">
                <NextLink href="/signup">Signup</NextLink>
              </li>
              <li className="mx-1">
                |
              </li>
              <li className="mx-1 hover:opacity-50">
                <NextLink href="/login">Login</NextLink>
              </li>
            </ul>
          </div>
          <div className="m-2 p-1 text-center bg-blue-200">
            © 2023 NextJS13 Sample
          </div>
        </div>
      </div>
    </footer>
  )
}

 

次に共通レイアウトファイル「src/app/layout.tsx」を以下のように修正し、作成したフッターを表示させます。

import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import Header from '@/components/common/Header'
import Footer from '@/components/common/Footer'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Header />
        {children}
        <Footer />
      </body>
    </html>
  )
}

 

ブラウザで「http://localhost:3000/」を確認し、PC版としては次のように表示されていればOKです。

 

タブレットやスマホ版なら次のように表示されればOKです。

 

TOPページにレスポンシブデザインのレイアウトを付ける

次はTOPページのファイル「src/app/page.tsx」にレスポンシブデザインのレイアウトを付けてみます。

「src/app/page.tsx」の中身を次のように修正します。

export default function Home() {
  return (
    <main className="w-full">
      <div id="main-visual" className="md:flex justify-between m-1 p-1 bg-red-100">
        <div className="md:w-1/2 md:h-64 flex justify-center m-1 p-1 bg-red-200">
          <div className="flex items-center">
            Main Visual left
          </div>
        </div>
        <div className="md:w-1/2 md:h-64 flex justify-center m-1 p-1 bg-red-200">
          <div className="flex items-center">
            Main Visual right
          </div>
        </div>
      </div>
      <div id="content1" className="flex justify-center m-1 p-1 bg-yellow-100">
        <div className="w-full h-64 flex justify-center items-center bg-yellow-200">
          Content1
        </div>
      </div>
      <div id="content2" className="flex justify-center m-1 p-1 bg-orange-100">
        <div className="w-full h-64 flex justify-center items-center bg-orange-200">
          Content2
        </div>
      </div>
    </main>
  )
}

 

ブラウザで「http://localhost:3000/」を確認し、PC版としては次のように表示されていればOKです。

 

タブレットやスマホ版なら次のように表示されればOKです。

 

このようにこれまでの知識を活かして上手くCSSを設定すると、上記のようにレスポンシブデザインのフロント画面を構築できます。

 



ヘッダーのボタンにスクロール機能を付ける

次はヘッダーにあるボタン「Content1」、「Content2」を押したら、TOPページの対象の部分にスクロールする機能を付けてみます。

今回はパッケージ「react-scroll」を利用する例をご紹介するため、以下のコマンドを実行してインストールします。

$ npm i react-scroll
$ npm i @types/react-scroll

 

次にヘッダーコンポーネント「Header.tsx」を次のように修正します。

'use client'
import BurgerMenu from '@/components/common/BurgerMenu';
import NextLink from "next/link";
import { Link as Scroll } from 'react-scroll';

export default function Header() {
  return (
    <header className="w-full sticky top-0 bg-gray-100">
      <nav className="p-1 bg-gray-200">
        <div className="hidden md:flex justify-between min-w-3xl bg-gray-300">
          <div className="flex items-center ml-1 text-xl font-bold">
            <Scroll
              to="main-visual"
              smooth={true}
              duration={600}
              offset={-50}
              className="hover:opacity-50 hover:cursor-pointer"
            >
              Logo
            </Scroll>
          </div>
          <div>
            <ul className="flex items-center">
              <li className="mx-2">
                <button className="font-medium">
                  <Scroll
                    to="content1"
                    smooth={true}
                    duration={600}
                    offset={-50}
                    className="hover:opacity-50 hover:cursor-pointer"
                  >
                    Content1
                  </Scroll>
                </button>
              </li>
              <li className="mx-2">
                <button className="font-medium">
                  <Scroll
                    to="content2"
                    smooth={true}
                    duration={600}
                    offset={-50}
                    className="hover:opacity-50 hover:cursor-pointer"
                  >
                    Content2
                  </Scroll>
                </button>
              </li>
              <li className="mx-2">
                <button className="m-1 py-1 px-3 border-2 rounded-lg bg-red-500 text-white hover:opacity-50">
                  <NextLink href="/signup">Signup</NextLink>
                </button>
              </li>
              <li className="mx-2">
                <button className="m-1 py-1 px-3 border-2 rounded-lg bg-slate-400 text-white hover:opacity-50">
                  <NextLink href="/login">Login</NextLink>
                </button>
              </li>
            </ul>
          </div>
        </div>
        <div className="md:hidden flex justify-between max-w-3xl bg-blue-200">
          <div className="text-xl font-bold">
            <Scroll
              to="main-visual"
              smooth={true}
              duration={600}
              offset={-50}
              className="hover:opacity-50 hover:cursor-pointer"
            >
              Logo
            </Scroll>
          </div>
          <div className="text-xl font-bold">
            <BurgerMenu />
          </div>
        </div>
      </nav>
    </header>
  )
}

 

合わせて「BurgerMenu.tsx」の方も次のように修正します。

'use client'
import { useState } from 'react';
import { slide as Menu, State } from 'react-burger-menu'
import NextLink from "next/link";
import { Link as Scroll } from 'react-scroll';

// Menuコンポーネントに適用させるCSS
const styles = {
  bmBurgerButton: {
    position: 'fixed',
    width: '32px',
    height: '26px',
    right: '20px',
    top: '5px',
  },
  bmBurgerBars: {
    background: 'black'
  },
  bmCross: {
    background: 'white'
  },
  bmMenuWrap: {
    position: 'fixed',
    height: '100%',
    top: "0",
  },
  bmMenu: {
    background: 'dimgray',
    padding: '2.5em 1.5em 0',
  },
  bmItemList: {
    color: 'white',
  },
}

export default function BurgerMenu() {
  // メニュー画面の開閉状態を管理する「isMenuOpen」を設定
  const [isMenuOpen, setIsMenuOpen] = useState(false)

  // メニューを閉じるための関数を設定
  const handleCloseMenu = () => {
    setIsMenuOpen(false)
  }

  // メニュー画面の開閉状態を確認するための関数を設定
  const handleStateChange = (state: State) => {
    setIsMenuOpen(state.isOpen)
  }

  return (
    <div id="outer-container">
      <Menu
        isOpen={isMenuOpen}
        onStateChange={handleStateChange}
        pageWrapId={'page-wrap'}
        outerContainerId={'outer-container'}
        right={true}
        styles={styles}
      >
        <main id="page-wrap">
          <ul className="flex flex-col">
            <li className="mb-4">
              <button className="hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                <Scroll
                  to="content1"
                  smooth={true}
                  duration={600}
                  offset={-50}
                  className="hover:opacity-50 hover:cursor-pointer"
                >
                  Content1
                </Scroll>
              </button>
            </li>
            <li className="mb-4">
              <button className="hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                <Scroll
                  to="content2"
                  smooth={true}
                  duration={600}
                  offset={-50}
                  className="hover:opacity-50 hover:cursor-pointer"
                >
                  Content2
                </Scroll>
              </button>
            </li>
            <li className="mb-4 flex justify-center">
              <button className="mt-4 p-2 w-3/4 text-3xl border-2 rounded-lg bg-red-500 hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                <NextLink href="/signup">Signup</NextLink>
              </button>
            </li>
            <li className="mb-4 flex justify-center">
              <button className="mt-4 p-1 w-3/5 border-2 rounded-lg bg-slate-400 hover:opacity-50"
                onClick={()=>{handleCloseMenu()}}
              >
                <NextLink href="/login">Login</NextLink>
              </button>
            </li>
          </ul>
        </main>
      </Menu>
    </div>
  )
}

 

これでスクロール機能の追加が完了したので、ブラウザから確認してみて下さい。

※スクロール機能を確認しづらい場合は、src/app/page.tsxのContent1とContent2の高さの設定を「h-96」とかに変更すると確認しやすいです。

 



Signupページを作る

次にSignupページの画面を作りますが、フォームを表示させる必要があるため、以下のコマンドを実行してパッケージ「react-hook-form」をインストールします。

$ npm i react-hook-form

 

次に以下のコマンドを実行し、signupページのファイルを作成します。

$ cd ..//..
$ cd app
$ mkdir signup
$ cd signup
$ touch page.tsx

 

ではsignupページのファイル「src/app/signup/page.tsx」の中身の例としては次のように記述します。

※この時点では実際のSignup機能はつけないため、Signupボタンを押した時の処理はフォームに入力された値をログに出力するだけにしています。

'use client'
import { useForm, SubmitHandler } from 'react-hook-form';

// フォームの入力項目
interface SignupFormInputs {
  email: string;
  password: string;
};

export default function Signup() {
  const { register, handleSubmit, formState: { errors } } = useForm<SignupFormInputs>();

  // Signupボタンの設定
  const signup: SubmitHandler<SignupFormInputs> = (formData) => {
    console.log(formData);
  };

  return (
    <main className="flex flex-col justify-center items-center w-full h-screen m-auto">
      <h1 className="text-2xl mb-8 border-b-2 w-2/3 max-w-lg pb-8 text-center">
        Signup
      </h1>
      <form onSubmit={handleSubmit(signup)}
        className="grid grid-cols-1 gap-10 w-2/3 max-w-lg"
      >
        <div className="flex flex-col">
          <label htmlFor="email">メールアドレス</label>
          <input id="email" type="email" className="bg-gray-100 rounded h-10"
            {...register('email',
              {
                required: "メールアドレスを入力して下さい。",
                maxLength: { value: 319, message: "319文字以下で入力して下さい。" }
              })
            }
          />
          <span className="text-red-600">
            {errors.email && errors.email.message}
          </span>
        </div>
        <div className="flex flex-col">
          <label htmlFor="password">パスワード</label>
          <input id="password" type="password" className="bg-gray-100 rounded h-10"
            {...register('password',
              {
                required: "パスワードを入力して下さい。",
                minLength: { value: 6, message: "6文字以上で入力して下さい。" },
                maxLength: { value: 128, message: "128文字以下で入力して下さい。" }
              })
            }
          />
          <span className="text-red-600">
            {errors.password && errors.password.message}
          </span>
        </div>
        <button type="submit" className="bg-blue-500 rounded-xl text-white h-10">
          Signup
        </button>
      </form>
    </main>
  )
}

 

ブラウザで「http://localhost:3000/signup」を確認し、PC版の場合は次のように表示されていればOKです。

 

ただし、Signupページにはヘッダーの部分の表示は不要なため、今回はTOPページにだけヘッダーを表示するように、ヘッダーコンポーネント「Header.tsx」を次のように修正します。

'use client'
import BurgerMenu from '@/components/common/BurgerMenu';
import NextLink from "next/link";
import { Link as Scroll } from 'react-scroll';
import { usePathname } from "next/navigation";
export default function Header() {
  // header表示可否のフラグを設定
  let headerDisplayFlag = false;

  // TOPページ(/)の場合のみフラグを有効にする
  const pathName = usePathname()
  if (pathName == '/') {
    headerDisplayFlag = true;
  }
  return (
    <> { headerDisplayFlag &&
    <header className="w-full sticky top-0 bg-gray-100">
      <nav className="p-1 bg-gray-200">
        <div className="hidden md:flex justify-between min-w-3xl bg-gray-300">
          <div className="flex items-center ml-1 text-xl font-bold">
            <Scroll
              to="main-visual"
              smooth={true}
              duration={600}
              offset={-50}
              className="hover:opacity-50 hover:cursor-pointer"
            >
              Logo
            </Scroll>
          </div>
          <div>
            <ul className="flex items-center">
              <li className="mx-2">
                <button className="font-medium">
                  <Scroll
                    to="content1"
                    smooth={true}
                    duration={600}
                    offset={-50}
                    className="hover:opacity-50 hover:cursor-pointer"
                  >
                    Content1
                  </Scroll>
                </button>
              </li>
              <li className="mx-2">
                <button className="font-medium">
                  <Scroll
                    to="content2"
                    smooth={true}
                    duration={600}
                    offset={-50}
                    className="hover:opacity-50 hover:cursor-pointer"
                  >
                    Content2
                  </Scroll>
                </button>
              </li>
              <li className="mx-2">
                <button className="m-1 py-1 px-3 border-2 rounded-lg bg-red-500 text-white hover:opacity-50">
                  <NextLink href="/signup">Signup</NextLink>
                </button>
              </li>
              <li className="mx-2">
                <button className="m-1 py-1 px-3 border-2 rounded-lg bg-slate-400 text-white hover:opacity-50">
                  <NextLink href="/login">Login</NextLink>
                </button>
              </li>
            </ul>
          </div>
        </div>
        <div className="md:hidden flex justify-between max-w-3xl bg-blue-200">
          <div className="text-xl font-bold">
            <Scroll
              to="main-visual"
              smooth={true}
              duration={600}
              offset={-50}
              className="hover:opacity-50 hover:cursor-pointer"
            >
              Logo
            </Scroll>
          </div>
          <div className="text-xl font-bold">
            <BurgerMenu />
          </div>
        </div>
      </nav>
    </header>
    } </>
  )
}

 

ブラウザで「http://localhost:3000/signup」や「http://localhost:3000/」を確認し、TOPページ以外にヘッダーが表示されなければOKです。

 

Loginページを作る

Signupページと同じ要領でLoginページも作っておきます。

$ cd ..
$ mkdir login
$ cd login
$ touch page.tsx

 

「src/app/login/page.tsx」の中身は次の通りです。

'use client'
import { useForm, SubmitHandler } from 'react-hook-form';

// フォームの入力項目
interface LoginFormInputs {
  email: string;
  password: string;
};

export default function Login() {
  const { register, handleSubmit, formState: { errors } } = useForm<LoginFormInputs>();

  // Signupボタンの設定
  const signup: SubmitHandler<LoginFormInputs> = (formData) => {
    console.log(formData);
  };

  return (
    <main className="flex flex-col justify-center items-center w-full h-screen m-auto">
      <h1 className="text-2xl mb-8 border-b-2 w-2/3 max-w-lg pb-8 text-center">
        Login
      </h1>
      <form onSubmit={handleSubmit(signup)}
        className="grid grid-cols-1 gap-10 w-2/3 max-w-lg"
      >
        <div className="flex flex-col">
          <label htmlFor="email">メールアドレス</label>
          <input id="email" type="email" className="bg-gray-100 rounded h-10"
            {...register('email',
              {
                required: "メールアドレスを入力して下さい。",
                maxLength: { value: 319, message: "319文字以下で入力して下さい。" }
              })
            }
          />
          <span className="text-red-600">
            {errors.email && errors.email.message}
          </span>
        </div>
        <div className="flex flex-col">
          <label htmlFor="password">パスワード</label>
          <input id="password" type="password" className="bg-gray-100 rounded h-10"
            {...register('password',
              {
                required: "パスワードを入力して下さい。",
                minLength: { value: 6, message: "6文字以上で入力して下さい。" },
                maxLength: { value: 128, message: "128文字以下で入力して下さい。" }
              })
            }
          />
          <span className="text-red-600">
            {errors.password && errors.password.message}
          </span>
        </div>
        <button type="submit" className="bg-blue-500 rounded-xl text-white h-10">
          Login
        </button>
      </form>
    </main>
  )
}

 



NextJS13をAWS Amplifyにデプロイする方法

次はAWS Amplifyにデプロイする方法について解説しますが、既にAWSアカウントは作成済みの前提で話を進めますので、もしまだアカウントを作成してない方は以下の記事を参考にするなどして用意して下さい。

※AWS Amplifyは使用料がかかるため、その点はご注意下さい。尚、無料でデプロイを試したい場合は下記記事を参考にVercelにデプロイして下さい。

関連記事👇

SPA構成のWebアプリケーションを開発する方法まとめ【Docker・NextJS(React)・Vercel・Rails7(APIモード)・AWS ECS(Fargate)】

2022年11月22日

 

AWSアカウントにログイン後、サービスを検索するなどして「AWS Amplify」を開きます。

 

次に画面下のAmplify ホスティングにある「使用を開始する」をクリックします。

 

次にGitHubを選択し、画面右下の「続行」をクリックします。

 

次にリポジトリ選択画面が表示されるので、対象のリポジトリのみ読み込む場合は「Only select 〜」を選択し、読み込みたいリポジトリを選択後、画面下の「Install & Authorize」をクリックします。

 

次にGitHubのパスワード入力画面が表示されるので、パスワードを入力して「Confirm」をクリックします。

 

これでリポジトリの読み込みまで完了したので、リポジトリの選択リストをクリックします。

 

対象のリポジトリとブランチを選択し、画面右下の「次へ」をクリックします。

 

次にビルド設定画面が表示されるので、画面下の「詳細設定」をクリックします。

 

次に画面下の「パッケージバージョンの上書きを追加」のリストをクリックします。

 

リストから「Node.js version」を選択します。

 

次にバージョンの項目に今回使っているNodeのバージョンである「18.13.0」を入力し、画面右下の「次へ」をクリックします。

※23年9月現在、Nodeのv18系を使いたい場合は「18.13.0」しか使えないっぽいのでご注意下さい。そのため、今回は最初からNodeのバージョンを「18.13.0」にしています。

 

次に画面右下の「保存してデプロイ」をクリックします。

 

これでデプロイ処理が開始されます。

 

画面のプロビジョン〜デプロイまで全て緑色になれば正常にデプロイが完了しているため、左側にあるリンク「https:main…」をクリックします。

 

ここまでNextJS13で開発してきたレスポンシブデザインの画面が表示され、想定通りの動作すればOKです。

 

AWS Amplifyにデプロイしたアプリを削除する方法

AWS Amplifyにアプリをデプロイしたままにしておくと料金が従量課金されていくため、一時的に使いたい方などはアプリの削除をするのを忘れないようにご注意下さい。

アプリを削除するには、画面右上の「アクション」リストから「アプリの削除」をクリックします。

 

アプリを削除するか聞かれるので、「削除」を入力後、右下にある「削除」をクリックします。

 

これでアプリが削除されればOKです。

 

最後に

今回はNextJS13でレスポンシブデザインのフロントエンド画面を開発する方法についてまとめました。

軽く使ってみた感じ、NextJS12以前より、NextJS13の方がフレームワークとして使いやすくなっているので、興味がある人やまだ使ったことがない人はぜひ一度使ってみていただければと思います。

また、Tailwind CSSを上手く設定すればレスポンシブデザインの画面構築が可能なので、興味がある方はぜひ今回の内容を参考にしてみて下さい。

 

各種SNSなど

各種SNSなど、チャンネル登録やフォローをしていただけると励みになるので、よければぜひお願いします!

 

The following two tabs change content below.

Tomoyuki

SEを5年経験後、全くの未経験ながら思い切ってブロガーに転身し、月間13万PVを達成。その後コロナの影響も受け、以前から興味があったWeb系エンジニアへのキャリアチェンジを決意。現在はWeb系エンジニアとして働きながら、プロゲーマーとしても活躍できるように活動中。








シェアはこちらから


おすすめのゲーミングPCまとめ

近年、eスポーツという言葉が浸透し、ゲーミングPCの需要も増えましたが、「ゲーミングPCはどう選べばいいの?」という人も多いのではないでしょうか。そんなPC初心者でも迷わず選べるよう、おすすめのゲーミングPCをご紹介します!


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です