React Hook Form 触ってみた

# React Hook Formとは
Reactと使用できるフォームバリデーションライブラリ。
React Nativeでも使用することが可能。

今回はもくもく会で、React Hook Formを使用したのでその所感と、学べたことを紹介していきます。

## 今回の紹介コード

```React:Login.tsx
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useForm } from "react-hook-form";

import { fetchAsyncLogin } from '../../../stores/slices/userSlice'
import { hot } from 'react-hot-loader'

import Header from '../../components/block/Header'
import Footer from '../../components/block/Footer'

interface loginFormInput {
  userName: string;
  passWord: string;
}

const Login = () => {
  const { register, handleSubmit, errors, reset } = useForm<loginFormInput>();
  const dispatch = useDispatch()
  const history = useHistory()

  const onSubmit = (data: FormData) => {
    dispatch(fetchAsyncLogin(data))
    reset()
  }


  return (
    <div>
      <Header />
      <h1 css={LoginTitle}>Login Page</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
        <input
          type="text"
          name="userName"
          aria-invalid={errors.userName ? "true" : "false"}
          ref={register({ required: true })}
          placeholder="user"
        />
        {errors.userName && errors.userName.type === "required" && <span role="alert">必須だよ！</span>}
        <input
          type="text"
          name="passWord"
          aria-invalid={errors.passWord ? "true" : "false"}
          ref={register({ required: true, pattern: /^[A-Za-z]+$/i })}
          placeholder="pass"
        ></input>
        {errors.passWord && errors.passWord.type === "required" && <span role="alert">必須だよ！</span>}
        {errors.passWord && errors.passWord.type === "pattern" && <span role="alert">半角英数字でお願いします！</span>}
        <input type="submit" />
      </form>
      <Footer />
    </div>
  )
}

export default hot(module)(Login)

```

## インストール
まず使用するにはインストールが必要

```terminal
$ npm install react-hook-form
```

## ライブラリをインポート
バリデーションチェックを行うファイルにて、`react-hook-form`をインポート

```js
import { useForm } from "react-hook-form";
```

## registerについて
紹介ファイルにて、以下のような記述がある。

```react
const { register, handleSubmit, errors, reset } = useForm<loginFormInput>();
```

ここでuseFormから取り出しているregisterは、バリデーションをチェックするinputをフックに登録するためのものである。

```react
<input
  type="text"
  name="userName"
  aria-invalid={errors.userName ? "true" : "false"}
  ref={register({ required: true })}
  placeholder="user"
/>
```
上記のコードのように`ref`に対して、`register`を設定するとinputのvalueをチェックし、取得できるようになる。

### バリデーションの種類

```react
<input
  type="text"
  name="userName"
  aria-invalid={errors.userName ? "true" : "false"}
  ref={register({ required: true })}
  placeholder="user"
/>
```
先ほどregisterの紹介を行いました。コードをみるとregister内に`required: true`と設定されている。
`register`内でこのような設定を行うと、どのような`バリデーション`を`チェック`を行うかを設定できるようになっている。
今回のコードの場合は必須かチェックを行うようになっている。
register内で設定できるバリデーションの種類は以下のようになっている。

- required
- min
- max
- minLength
- maxLength
- pattern
- validate

## エラー表示について
エラー表示する際にはerrorsオブジェクトを定義しないといけません

```react
const { register, handleSubmit, errors, reset } = useForm<loginFormInput>();
```
上記のようにerrorsを定義することで準備完了です。

```react
<input
  type="text"
  name="userName"
  aria-invalid={errors.userName ? "true" : "false"}
  ref={register({ required: true })}
  placeholder="user"
/>
{errors.userName && errors.userName.type === "required" && <span role="alert">必須だよ！</span>}
```
上記コードのようにerrors.{name属性名}でエラーを確認することができる。

## useFormの初期設定について
userForm()とされているが実は()内は省略されている記述が存在する。

それはuseFormの設定である。

```jsx
const { register } = useForm({
  mode: 'onSubmit',
  reValidateMode: 'onChange',
  defaultValues: {},
  resolver: undefined,
  context: undefined,
  criteriaMode: "firstError",
  shouldFocusError: true,
  shouldUnregister: true,
})
```

デフォルトではこのように設定されている。

なので初期バリデーションはmodeで設定されているonSubmitを元に行われている。
ということはこのonSubmitを変更すれば他のイベントリスナーでバリデーションを行える。
### 設定できるmode(イベントリスナー)の種類
- onSubmit(Default)
- onBlur
- onChange
- onTouched
- all

## アクセシビリティについて
以下のコードのように、`aria-invalid`属性を記述しさらに`role="alert"`を記述することでどのname属性がどのようなエラーメッセージかをスクリーンリーダーで確認できるようになる。

```react
 <input
   type="text"
   name="userName"
   aria-invalid={errors.userName ? "true" : "false"}
   ref={register({ required: true })}
   placeholder="user"
 />
{errors.userName && errors.userName.type === "required" && <span role="alert">必須だよ！</span>}
```

## おわり
一旦ざっとアウトプットしてみましたがまだまだ理解不足な箇所があるので、随時更新もしくは新しく記事を書いていきたいと思います。

## 参照記事
[React Hook Form](https://react-hook-form.com/jp/)