技術メモ

プログラミングとか電子工作とか

React Hook Form入門 その1(導入編)

f:id:ysmn_deus:20200224171811p:plain

去年はNuxt.jsやNext.jsなど色々触ってたんですが、結局プレーンなReactが扱いやすいんじゃないかと思い色々試行錯誤しています。(Nextは結構良い感じだったんですが、Amplifyとの相性が悪くて不採用となりました)
基本的にはReact + Reduxの組み合わせが便利だと思い利用していたのですが、極力React Hooksを利用した方がシンプルな状態管理ができそうなので(きちんと理解してないのでレンダリングのタイミングでStateを変更してしまったり・・・)フォームはRedux FormからReact Hook Formに移行しようと思います。

この記事ではReact Hook Formに慣れるためにアプリケーションを作成しながら基本的な機能を確認していきます。

初期設定

Reactのプロジェクト作成(create-react-app)

プロジェクトを作成します。この辺は基本的なReactのプロジェクト作成と同じで、create-react-appを利用します。

create-react-app . --template typescript

(コマンドはプロジェクト用のディレクトリ内で実行してます。)

とりあえず実行

まずはプロジェクトとして問題無いことを確認しておきましょう。
基本的にパッケージマネージャーはyarnを利用します。

yarn start

f:id:ysmn_deus:20200224133318p:plain
いつもの

プロジェクトとしてはOKです。
一応ガッツリ開発するわけではないですが、ESLint + Prettierの設定なども個人的によく忘れるので行っておきます。

ESLint + Prettier

ESLintのインストール

まずはESLintをインストールしていきます。
TypeScriptでの開発を想定しているので、@typescript-eslint/parser@typescript-eslint/eslint-pluginも合わせてインストールします。

yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin

ESLintの設定

プロジェクトのルートディレクトリ(create-react-appした場所)に.eslintrc.jsを作成します。

module.exports = {
    env: {
        browser: true,
        node: true,
        es6: true
    },
    parser: '@typescript-eslint/parser',
    parserOptions: {
        ecmaFeatures: {
            jsx: true
        },
        sourceType: "module"
    },
    plugins: [
        "react",
        '@typescript-eslint'
    ],
    extends: [
        "eslint:recommended",
        "plugin:react/recommended",
        'plugin:@typescript-eslint/recommended',
    ],
    rules: {
    },
    overrides: [
        {
            'files': ["**/*.tsx"],
            'rules': {
                'react/prop-types': 'off'
            }
        }
    ]
};

とりあえず動けばいいのでこんなもんで。
詳しい説明とかは今回は省きます。

package.jsonにLint用のコマンドを記述します。

~
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "lint": "eslint --ext .ts,.js,.tsx,.jsx --ignore-path .gitignore ."
  },
~

ここまでできたら、試しに実行します。

yarn lint

errorとwarningが色々出てくると思いますが、eslintが動いてる証拠なので問題無いです。

Prettierのインストール

ESLintの設定ができたら次はPrettierをインストールします。
ESLintとの競合などにも対応するためeslint-config-prettiereslint-plugin-prettierも合わせてインストールしておきます。

yarn add -D prettier @types/prettier @types/eslint-plugin-prettier eslint-config-prettier eslint-plugin-prettier

Prettierの設定

基本的にESLintの補助機能として利用するため、ESLintの設定に追記します。

module.exports = {
  env: {
    browser: true,
    node: true,
    es6: true
  },
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    },
    sourceType: "module"
  },
  plugins: [
    'prettier',
    "react",
    '@typescript-eslint'
  ],
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
    'prettier/@typescript-eslint'
  ],
  rules: {
    'prettier/prettier': [
      'error',
      {
        'semi': false,
        'trailingComma': "all"
      }
    ]
  },
  overrides: [
    {
      'files': ["**/*.tsx"],
      'rules': {
        'react/prop-types': 'off'
      }
    }
  ]
};

基本的に上記の設定で動くとは思います。
試しに実行してみましょう。

yarn lint

errorやwarningがでれば問題ありません。
おそらくこの後保存されれば自動でlintが走るようにすると思いますが、lintの設定で勝手に整形するには--fixオプションを付けます。
試しに付けて実行します。

yarn lint --fix

大部分が勝手に修正されました。
ここで、直らないファイルで、errorのものは

  • App.test.tsx
  • serviceWorker.ts

の二種類かと思います。
今回テストは書かないので、App.test.tsxは削除して対応しますが、testexpectが未定義というエラーなので、おそらくeslint-plugin-jestとか入れれば直ると思います。
serviceWorker.tsに関しては、基本触らないファイルなので、該当箇所のみ無視する様に修正します。

~
        checkValidServiceWorker(swUrl, config) // eslint-disable-line @typescript-eslint/no-use-before-define
~
        registerValidSW(swUrl, config) // eslint-disable-line @typescript-eslint/no-use-before-define
~

対応後にもう一度lintを走らせます。

yarn lint

errorは消えてwarningだけになったかと思います。
warningも気になる人は対応してください。(serviceWorker.tsはファイルごと無視してもいいかもしれません。)

ESLint + Prettierのその他の設定

ファイルウォッチャーに登録する(保存したら勝手に処理する)のは、開発環境によって異なるので省きます。

TypeScript

tsconfig.json

incrementalの設定とexcludeの設定を追記しておきます。

~
    "jsx": "react",
    "baseUrl": "src",
    "incremental": true
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
~

React Hook Form

ようやく本題です。

インストール

インストールは至って簡単です。

yarn add react-hook-form

これで使用可能になります。

基本的な利用方法

試しにクイックスタートのサンプルを利用してみます。
基本的には書いてある通りでいいんですが、TypeScriptだとコンパイル時にエラーが出るので、余計なコメントなどを修正します。

import React from "react"
import { useForm } from "react-hook-form"

export default function App() {
  const { register, handleSubmit, watch, errors } = useForm()
  const onSubmit = (data: any) => {
    console.log(data)
  }

  console.log(watch("example"))

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="example" defaultValue="test" ref={register} />

      <input name="exampleRequired" ref={register({ required: true })} />
      {errors.exampleRequired && <span>This field is required</span>}

      <input type="submit" />
    </form>
  )
}

とりあえず使えるか実行して確認します。

yarn start

超シンプルですが、フォームが出てきました。

f:id:ysmn_deus:20200224144121p:plain

2個目の入力フォームが必須のようなので、適当に値を入れて「送信」を押します。

f:id:ysmn_deus:20200224144425p:plain

基本的にはformのonSubmituseFormというHookを利用して得たhandleSubmitという関数を通じて、handleSubmitに渡した関数がフォームのデータを引数に貰って実行されるようです。
また、watchという関数はフォームの変化を監視しているようで、testと記載されているフォームを編集するとconsole.log(watch('example'))が毎回発火します。

f:id:ysmn_deus:20200224144752p:plain

長くなったのでバリデーションとかはまた次回に。