去年は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
プロジェクトとしては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-prettier
とeslint-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
は削除して対応しますが、test
やexpect
が未定義というエラーなので、おそらく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
超シンプルですが、フォームが出てきました。
2個目の入力フォームが必須のようなので、適当に値を入れて「送信」を押します。
基本的にはformのonSubmit
にuseForm
というHookを利用して得たhandleSubmit
という関数を通じて、handleSubmit
に渡した関数がフォームのデータを引数に貰って実行されるようです。
また、watch
という関数はフォームの変化を監視しているようで、test
と記載されているフォームを編集するとconsole.log(watch('example'))
が毎回発火します。
長くなったのでバリデーションとかはまた次回に。