株式会社エイチームコマーステックのkazzです。
タイトルの通り、今回は React 用のフォームライブラリである react-final-form
から react-hook-form
への移行について、開発での実体験を交えながら軽めにお話しできたらと思います。
なぜ移行するのか
フォームの開発をしやすくするために react-final-form
を使って開発をしていましたが、1年半ほど改修を繰り返す中で、 react-final-form
の以下の点が目につくようになりました。
- 不具合が多く、かつ中々対応されない
- 直近のcommit・リリースが少ない
- 比較的、ドキュメントが不充実
要するに、メンテが不十分であることが要因で色々と不都合が起こるようになってきました。そして、大きめの改修をキッカケに、 react-hook-form
への移行を決意しました。
hook-form の選定
hook-form
でシステムに必要な機能要件も満たしていそうであり、かつ実行パフォーマンスに関してもバンドルサイズもトータルで僅かに減で、非制御コンポーネントにより再レンダリングを抑えやすくなったため、パフォーマンス改善も見込めました。
react-final-form + final-form | react-hook-form | (formik) | |
---|---|---|---|
bundled size (minified) | 25.8kB | 25.1kB | 44.3kB |
control | 制御コンポーネント | 非制御コンポーネント | 制御コンポーネント |
メンテナンス | 1年で4commits | たくさん | ほぼなし |
ドキュメント(主観) | 見ずらい | 見やすい | 見やすい |
移行作業
1. コンポーネントの作り直し
共通化しているコンポーネント・処理が final-form
にがっつり依存していることが判明。該当のフォームだけを順々に直していく想定でいましたが、共通部分からの作り直しが必要になってしまいました。
このフェーズでは、新たなディレクトリへ hook-form
でも使えるコンポーネントの実装を行いました。合わせて、formとUIの疎結合化も進めてます。
これを、
// こんな感じで、外枠から final-form に依存している
import { Field } from 'react-final-form';
...
const InputText = () => {
return <Field>...</Field>
}
このようにUIとformに分けて実装することで、処理の見通しも良くなり、共通化部分とformが疎結合になりました。
import { useController } from 'react-hook-form';
// 純粋なUIコンポーネント
const InputText = ({onChange, onBlur, ref, ...}) => {
return <input onChange={onChange} onBlur={onBlur} ref={ref} />
}
// formに関わる処理をラップしたコンポーネント
const InputTextForHookForm = ({control, registerName, ...rest}: {control: Control, control: string ...}) => {
const { field } = useController({ control, name: registerName});
return <InputText {...field} />
}
hook-form
は イベントハンドラーやrefを正しく末端まで引き継いであげればライブラリの機能をしっかり使えるので、その点はこのformとUIの疎結合化はしやすかったかなと思います。
2. form部分の作り替え
これは一律でやるもの予定はなく、改修のたびに置き換えていくよう進めてます。
非制御コンポーネントの扱いは最初は慣れませんでしたが、 useWatch
のようなAPIを活用していくことで、欲しい部分に再レンダリングを挟みつつレンダリングの回数を抑える実装ができるので使い勝手は良いです。
制御・非制御コンポーネントの違いを先に理解しておくのはMUSTかと思います。
3. 後処理
置き換えを進める中で不要になり次第既存のコンポーネントを消していったり、ライブラリ自体の削除をします。final-form
はそれなりにサイズも大きいので、忘れず行います。
最後に
不具合やドキュメントの見づらさから、開発体験を大きく落としている部分だと感じながら開発していたので、移行作業ができていることは嬉しく思います。
最近は、React も Next.js もどんどん新機能が出てくる中で、メンテ不足により機能追従がされなくなる不安もあったため、今後のためを思い移行を進めました。
今回は全体の流れをさらっと説明しましたが、各項目でここをもっと具体的に知りたいなど要望があれば、別記事で出そうかなと思います。
次回アドベントカレンダーの投稿は、@o93 さんの 「誤差と あいまいさと 不確かさと」 です!