この記事では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を開いて中身を以下のように書き換えます。
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というファイルを新しく作成して、中身を以下のように書いてください。
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;
実際に、このフォームのページを開くと以下のような画面になります。
このフォームはFormLabelやInputなどのChakra UIのコンポーネントを使って作成しており、フォームが送信されたときにonSubmitというReact Hook Formの関数が実行されるように設定しています。
今回、onSubmit関数の中にはフォームで送信された値をコンソールに出力する処理を書いています。
実際にフォームで値を入力して送信し、コンソールに送信したデータが表示されるかどうかを確認してみてください。
バリデーションを書く
先ほど作成したフォームにバリデーションを追加していきます。各項目のバリデーションはそれぞれ以下のように設定します。
-
ユーザー名
必須、50文字以内 -
メールアドレス
必須、8文字以上、50文字以内、メールアドレスの形式で半角英数字のみ -
パスワード
必須、8文字以上、50文字以内、半角英数字のみ -
確認パスワード
必須、8文字以上、50文字以内、半角英数字のみ、パスワードと一致している
まず、Chakra UIからエラーメッセージのコンポーネントであるFormErrorMessageをインポートします。
import {
// FormErrorMessageを追加
FormErrorMessage,
FormLabel,
FormControl,
Input,
Button,
Box,
} from '@chakra-ui/react'
次にform.tsxのuseFormの定義を以下のように変更します。
// React Hook Formでバリデーションやフォームが送信されたときの処理などを書くために必要な関数
const {
handleSubmit,
register,
// getValuesを追加
getValues,
formState: { errors, isSubmitting },
} = useForm<formInputs>()
パスワードと確認パスワードが一致しているかどうかのバリデーションを作成するためにReact Hook FormのgetValuesという関数が必要になるので追加しておきます。
ここからは実際にフォームの項目にバリデーションを作成していきます。
まずはユーザー名のバリデーションを作成します。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のバリデーションのエラーメッセージは
{errors.name && errors.name.message}
といった書き方で表示させることができます。ただ、React Hook Formのエラーメッセージは装飾されていないただのテキストになっているので、Chakra UIのFormErrorMessageコンポーネントを使って装飾されたエラーメッセージとして表示されるようにします。
エラーメッセージと入力欄は、FormControlのコンポーネントにisInvalidをつけることで連動させています。
<FormControl isInvalid={Boolean(errors.name)} mb={5}>
同様に、
- メールアドレス
- パスワード
- 確認パスワード
にもバリデーションをつけていくと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の関数を使うことで実装できます。
{...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のリポジトリはこちらです。