5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Next.js + TypeScript】React Hook FormとChakra UIでフォームとバリデーションを作成する

Last updated at Posted at 2023-03-02

この記事ではReact Hook FormとChakra UIを使って、Next.jsのフォームとバリデーションと作成する方法を解説していきます。また、今回はTypeScriptを使用します。

Chakra UIとReact Hook Formを使うことで、整ったデザインのフォームを簡単につくることができます。また、バリデーションを作成するための関数もReact Hook Formで用意されているので、それを使うことでバリデーションも簡単に実装できます。

開発環境

  • macOS Catalina 10.15.7
  • Next.js 13.2.2
  • react-hook-form 7.43.2
  • Chakra UI 2.5.1

プロジェクトの作成

Next.jsのプロジェクトを作成します。

npx create-next-app

コマンドを入力するとプロジェクト名を聞かれるので、何か適当な名前をつけてください。また、TypeScriptを使うかどうかも聞かれるのでYesを選択してください。

作成が完了したらプロジェクトのディレクトリに移動して、以下のコマンドを実行します。

npm install
npm run dev

http://localhost:3000/ にアクセスし、Next.jsの初期画面が表示されることを確認してください。

Chakra UIのインストールと設定

次に、Chakra UIのインストールと設定を行います。ターミナルで以下のコマンドを入力してChakra UIをインストールしてください。

npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion

インストールが完了したら_app.tsxを開いて中身を以下のように書き換えます。

_app.tsx
import type { AppProps } from 'next/app'
import { ChakraProvider } from '@chakra-ui/react'

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

これでChakra UIを使うための準備が完了しました。

React Hook Formのインストール

続いてはReact Hook Formをインストールします。ターミナルで以下のコマンドを入力し、React Hook Formをインストールしてください。

npm install react-hook-form

ここからは先ほどインストールしたChakra UIとReact Hook Formでフォームを作成していきます。

フォームの作成

今回作成するフォームの項目は

  • ユーザー名
  • メールアドレス
  • パスワード
  • 確認パスワード

の4つです。

Next.jsのプロジェクトのpagesディレクトリにform.tsxというファイルを新しく作成して、中身を以下のように書いてください。

form.tsx
import { useForm } from 'react-hook-form'
import {
  FormLabel,
  FormControl,
  Input,
  Button,
  Box,
} from '@chakra-ui/react'

// フォームで使用する変数の型を定義
type formInputs = {
  name: string;
  email: string;
  password: string;
  passwordConfirm: string;
}

const RegisterForm = () => {
  // React Hook Formでバリデーションやフォームが送信されたときの処理などを書くために必要な
  const {
    handleSubmit,
    register,
    formState: { errors, isSubmitting },
  } = useForm<formInputs>()

  // フォームが送信されたときの処理
  const onSubmit = handleSubmit((data) => {
    // フォームで入力されたデータをコンソールに表示
    console.log(data)
  });

  return (
    <Box m={4}>
      <form onSubmit={onSubmit}>
        {/* 名前 */}
        <FormControl mb={5}>
          <FormLabel htmlFor='name'>ユーザー名</FormLabel>
          <Input
            id='name'
            {...register('name', {
              // 後ほどここにバリデーションを追加
            })}
          />
        </FormControl>
        {/* メールアドレス */}
        <FormControl mb={5}>
          <FormLabel htmlFor='email'>メールアドレス</FormLabel>
          <Input
            id='email'
            {...register('email', {
              // 後ほどここにバリデーションを追加
            })}
          />
        </FormControl>
        {/* パスワード */}
        <FormControl mb={5}>
          <FormLabel htmlFor='password'>パスワード</FormLabel>
          <Input
            id='password'
            type='password'
            {...register('password', {
              // 後ほどここにバリデーションを追加
            })}
          />
        </FormControl>
        {/* 確認パスワード */}
        <FormControl mb={5}>
          <FormLabel htmlFor='passwordConfirm'>確認パスワード</FormLabel>
          <Input
            id='passwordConfirm'
            type='password'
            {...register('passwordConfirm', {
              // 後ほどここにバリデーションを追加
            })}
          />
        </FormControl>
        <Button mt={4} colorScheme='blue' isLoading={isSubmitting} type='submit'>
          送信
        </Button>
      </form>
    </Box>
  )
}

export default RegisterForm;

実際に、このフォームのページを開くと以下のような画面になります。
スクリーンショット 2023-02-28 16.31.47.png

このフォームはFormLabelやInputなどのChakra UIのコンポーネントを使って作成しており、フォームが送信されたときにonSubmitというReact Hook Formの関数が実行されるように設定しています。

今回、onSubmit関数の中にはフォームで送信された値をコンソールに出力する処理を書いています。

実際にフォームで値を入力して送信し、コンソールに送信したデータが表示されるかどうかを確認してみてください。
スクリーンショット 2023-02-28 15.22.50.png

バリデーションを書く

先ほど作成したフォームにバリデーションを追加していきます。各項目のバリデーションはそれぞれ以下のように設定します。

  • ユーザー名
    必須、50文字以内

  • メールアドレス
    必須、8文字以上、50文字以内、メールアドレスの形式で半角英数字のみ

  • パスワード
    必須、8文字以上、50文字以内、半角英数字のみ

  • 確認パスワード
    必須、8文字以上、50文字以内、半角英数字のみ、パスワードと一致している

まず、Chakra UIからエラーメッセージのコンポーネントであるFormErrorMessageをインポートします。

form.tsx
import {
  // FormErrorMessageを追加
  FormErrorMessage,
  FormLabel,
  FormControl,
  Input,
  Button,
  Box,
} from '@chakra-ui/react'

次にform.tsxのuseFormの定義を以下のように変更します。

form.tsx
  // React Hook Formでバリデーションやフォームが送信されたときの処理などを書くために必要な関数
  const {
    handleSubmit,
    register,
    // getValuesを追加
    getValues,
    formState: { errors, isSubmitting },
  } = useForm<formInputs>()

パスワードと確認パスワードが一致しているかどうかのバリデーションを作成するためにReact Hook FormのgetValuesという関数が必要になるので追加しておきます。

ここからは実際にフォームの項目にバリデーションを作成していきます。

まずはユーザー名のバリデーションを作成します。form.tsxのフォームにあるユーザー名の項目の部分を以下のように書き換えてください。

form.tsx
{/* ユーザー名 */}
<FormControl isInvalid={Boolean(errors.name)} mb={5}>
  <FormLabel htmlFor='name'>ユーザー名</FormLabel>
  <Input
    id='name'
    // バリデーション
    {...register('name', {
      required:'必須項目です',
      maxLength: { value: 50, message: '50文字以内で入力してください' },
    })}
  />
  <FormErrorMessage>
    {errors.name && errors.name.message}
  </FormErrorMessage>
</FormControl>

registerというReact Hook Formで用意されている関数を使って、必須と50文字以内のバリデーションをつけています。

React Hook Formのバリデーションのエラーメッセージは

form.tsx
    {errors.name && errors.name.message}

といった書き方で表示させることができます。ただ、React Hook Formのエラーメッセージは装飾されていないただのテキストになっているので、Chakra UIのFormErrorMessageコンポーネントを使って装飾されたエラーメッセージとして表示されるようにします。

エラーメッセージと入力欄は、FormControlのコンポーネントにisInvalidをつけることで連動させています。

form.tsx
    <FormControl isInvalid={Boolean(errors.name)} mb={5}>

同様に、

  • メールアドレス
  • パスワード
  • 確認パスワード

にもバリデーションをつけていくとform.tsxは以下のようになります。

form.tsx
import { useForm } from 'react-hook-form'
import {
  // FormErrorMessageを追加
  FormErrorMessage,
  FormLabel,
  FormControl,
  Input,
  Button,
  Box,
} from '@chakra-ui/react'

// フォームで使用する変数の型を定義
type formInputs = {
  name: string;
  email: string;
  password: string;
  passwordConfirm: string;
}

const RegisterForm = () => {

  // React Hook Formでバリデーションやフォームが送信されたときの処理などを書くために必要な関数
  const {
    handleSubmit,
    register,
    // getValuesを追加
    getValues,
    formState: { errors, isSubmitting },
  } = useForm<formInputs>()

  // フォームが送信されたときの処理
  const onSubmit = handleSubmit((data) => {
    // フォームで入力されたデータをコンソールに表示
    console.log(data)
  });

  return (
    <Box m={4}>
      <form onSubmit={onSubmit}>
        {/* ユーザー名 */}
        <FormControl isInvalid={Boolean(errors.name)} mb={5}>
          <FormLabel htmlFor='name'>ユーザー名</FormLabel>
          <Input
            id='name'
            // 必須と50文字以内のバリデーション
            {...register('name', {
              required:'必須項目です',
              maxLength: { value: 50, message: '50文字以内で入力してください' },
            })}
          />
          <FormErrorMessage>
            {errors.name && errors.name.message}
          </FormErrorMessage>
        </FormControl>
        {/* メールアドレス */}
        <FormControl isInvalid={Boolean(errors.email)} mb={5}>
          <FormLabel htmlFor='email'>メールアドレス</FormLabel>
          <Input
            id='email'
            // 必須、50文字以内、半角英数字メールアドレス形式のバリデーション
            {...register('email', {
              required:'必須項目です',
              maxLength: { value: 50, message: '50文字以内で入力してください' },
              pattern: { value: /^[a-zA-Z0-9-_\.]+@[a-zA-Z0-9-_\.]+$/, message: 'メールアドレスを入力してください' },
            })}
          />
          <FormErrorMessage>
            {errors.email && errors.email.message}
          </FormErrorMessage>
        </FormControl>
        {/* パスワード */}
        <FormControl isInvalid={Boolean(errors.password)} mb={5}>
          <FormLabel htmlFor='password'>パスワード</FormLabel>
          <Input
            id='password'
            type='password'
            // 必須、8文字以上、50文字以内、半角英数字のバリデーション
            {...register('password', {
              required:'必須項目です',
              minLength: { value: 8, message: '8文字以上で入力してください' },
              maxLength: { value: 50, message: '50文字以内で入力してください' },
              pattern: { value: /^[0-9a-zA-Z]*$/, message: '半角英数字で入力してください' },
            })}
          />
          <FormErrorMessage>
            {errors.password && errors.password.message}
          </FormErrorMessage>
        </FormControl>
        {/* 確認パスワード */}
        <FormControl isInvalid={Boolean(errors.passwordConfirm)} mb={5}>
          <FormLabel htmlFor='passwordConfirm'>確認パスワード</FormLabel>
          <Input
            id='passwordConfirm'
            type='password'
            // 必須、8文字以上、50文字以内、半角英数字、パスワードと一致するかのバリデーション
            {...register('passwordConfirm', {
              required:'必須項目です',
              minLength: { value: 8, message: '8文字以上で入力してください' },
              maxLength: { value: 50, message: '50文字以内で入力してください' },
              pattern: { value: /^[0-9a-zA-Z]*$/, message: '半角英数字で入力してください' },
              validate: (value) => value === getValues("password") || "パスワードが一致しません",
            })}
          />
          <FormErrorMessage>
            {errors.passwordConfirm && errors.passwordConfirm.message}
          </FormErrorMessage>
        </FormControl>
        <Button mt={4} colorScheme='blue' isLoading={isSubmitting} type='submit'>
          送信
        </Button>
      </form>
    </Box>
  )
}

export default RegisterForm;

メールアドレスの形式になっているかどうかのバリデーションや、半角英数字になっているかどうかのバリデーションは正規表現を使って実装します。

また、確認パスワードがパスワードと一致しているかどうかというバリデーションに関しては、getValuesというReact Hook Formの関数を使うことで実装できます。

form.tsx
{...register('passwordConfirm', {
  required:'必須項目です',
  minLength: { value: 8, message: '8文字以上で入力してください' },
  maxLength: { value: 50, message: '50文字以内で入力してください' },
  pattern: { value: /^[0-9a-zA-Z]*$/, message: '半角英数字で入力してください' },
  validate: (value) => value === getValues("password") || "パスワードが一致しません",
})}

バリデーションの作成が終わったら、実際に http://localhost:3000/form にアクセスしてバリデーションが正常に機能しているかどうかを確認してみましょう。

まとめ

Chakra UIにはフォームの入力欄やエラーメッセージのコンポーネントが用意されており、Chakra UIを使うことで、整ったデザインのフォームを簡単に作ることができます。また、必須や半角英数字のみのバリデーションなどもReact Hook Formで簡単に実装できます。

今回の実装のgithubのリポジトリはこちらです。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?