変化の激しいReactへのライブラリ導入で考えるべきこと
この記事について
オープンロジのエンジニアrikuto(@riku929hr)です。
オープンロジは2023年12月で10周年を迎えました🎉
プロダクトはReactの黎明期からReactを利用して動いており、長年プロダクトを支えて来たコードである一方、ライブラリは古いままのものもあり、今のReactに適していないものがあります。
昨年(2023年)、オープンロジのフロントエンド環境にTypeScriptが導入され、環境が良くなってきました。
そしてこれを契機に、特に課題感のあったフォームライブラリの刷新のため、React Hook Formとyupを導入しました。
この記事ではこの2つのライブラリ導入に至るまでの過程を紹介し、変化の激しいフロントエンド環境におけるライブラリ選定について考えていきます[1]。
ライブラリ選定の基準
先に結論を言っちゃいます!
今回ライブラリ導入にあたって以下のようなことを考えました。
- 継続してメンテナンスされそうか
- 必要な情報にリーチしやすいか
- 扱いやすいか
それぞれ詳しく見ていきます。
1. 継続してメンテされそうか
使うライブラリがメンテされなくなると、別のライブラリなどに移行する作業が必要になる可能性が高いです。そうなると、なかなかバージョンアップが進まず開発生産性を損なったり、場合によってはセキュリティの問題が出てきたりしてしまいます。
そのため、メンテナンスが止まる可能性が高いものや、ニッチすぎるものは避けたほうが良いでしょう。
具体的な観点を挙げると以下のようなものがあります。
- 新しすぎないか
- experimentalなライブラリでないか
- 動作が不安定だとバグの原因にもなるので注意
- スポンサーの有無・開発元の状況はどうか
- 実績があると安心
- デファクトスタンダードに近いものか
- github star数、ダウンロード数、情報量などから総合的に判断する
- ユーザー数が多ければ、レガシーになったとしても継続的にメンテされるかもしれない
2. 必要な情報にリーチしやすいか
ライブラリの使い方に困ったときに、参照できる情報があると安心です。
自分以外の他のエンジニアが必要な情報にたどり着きやすいと、チームへの浸透が楽になります。
公式ドキュメントの充実度はもちろん、ブログやzenn等の記事の多さも含まれます。ベストプラクティスが定まっていると一層安心です。
また、1.で挙げた「新しすぎないか」ということとも関係しますが、新しすぎると情報量が少なく実装に困るので、ある程度成熟していたほうがいいのではないかと思っています。
3. 扱いやすいか
個人で使う範囲内であれば自由な選択ができますが、チーム開発となると適切に利用・運用されていくかに重きをおく必要があります。
たとえば以下のような観点で、できる限り開発チームに負担の少ないものを選定できると良いでしょう。
- 多機能すぎないか
- 多機能すぎると、情報量が多すぎて必要な情報にたどり着きにくかったり、実装に迷ったりします
- 不必要に高度なスキルが要求されたりしないか
- スキルレベルに加え、覚える事項が多いのも、いちいちリファレンスを参照する必要があって大変です
今回のライブラリ選定に至るまで
ここからは今回のライブラリを選定するまでに考えたことを紹介します。
そもそも、フォームライブラリって何?
簡単に言ってしまえば、フォームを作成する手間を省くためのライブラリです。
フォームの入力値を管理し、それをサーバーへ送信するという一連の流れはどんなフォームでも変わりません。
フォームを作るたびにそのような実装をイチから行うと、車輪の再発明になってしまい、機能開発する上では手間になってしまいます。
そのような実装を提供するライブラリを、一般的に「フォームライブラリ」と呼んでいます。
これによりコード量を減らすことができ、開発者がより重要な課題に注力することができる、というメリットがあります。
書籍や記事によってはフォームヘルパーと言ったりします。フォームを作成するのを助けるもの(ヘルパー)ということです。
個人的にはこっちのほうがしっくりきます。
新しいフォームライブラリ導入のモチベーション
オープンロジのコードはこれまで、フォームの作成にRedux Formというライブラリを利用することが多かったようです。
Redux全盛期に使われていたライブラリで、フォームの値をreduxのstateで管理するのが特徴です。
しかしRedux公式ガイドにも書かれている通り、フォームの値をreduxで管理するのは現在ではアンチパターンです。
理由をいくつか上げれば、パフォーマンスが悪くなったり、設計上良くなかったりします[2]。
こうした事情もあり、今は作者が自ら「使わないでください」と注意書きをしています[3]。
したがって、これから書くコードに関しては、Redux Formを使うのは得策ではありません。
こうした事情から、今回フォームライブラリを新たに導入することにしました。
React Hook Formの選定理由
2024年1月現在、主流となっているライブラリは次の3つです。
それぞれの特徴を簡単に示します。
-
React Hook Form
- この3つの中では最もダウンロード数が多い
- ドキュメントが充実しており、解説記事や書籍も多い
- Uncontrolled Componentを使うことで、レンダリングコストを最小化している。反面、react-selectなどのControlled Componentとの併用がちょっと面倒
-
Formik
- React Hook Formが登場する前に覇権を握っていたライブラリ
- React Hooks登場前のライブラリのためか、Hooksでの実装の事例やドキュメントがほとんどない
-
React Final Form
- Redux Formの作者による、Redux Form後継ライブラリ
- インターネット上の情報量は、この3つの中では最も少ない
npm trendsを見ると、React Hook Formの一人勝ちという状態です。
上記の通り、Reactのフォームライブラリについては、2024年1月現在ではReact Hook Form一択のようです。
「ライブラリ選定の基準」で述べた3つの観点をすべて満たしています。特に、デファクトスタンダードになっていることが大きな強みです。
その他のライブラリではHooksによる実装例が少なく、開発に困りそうな印象でした。
yup(バリデーションライブラリ)とは
React Hook Formにはresolverという機能があり、外部のライブラリを用いてバリデーションを行い、その結果をReact Hook Formで受け取り制御することができます。
もちろんReact Hook Form自体にもバリデーションの機能はあるようですが、このresolverとバリデーションライブラリを用いるのが一般的なようです[4]。
Hook Formがサポートしているのは、yup、zod、joiなどがありますが、このサポートされているライブラリの中から選定する必要があります。
yupの選定理由
最近、React Hook Formとの組み合わせでスタンダードになっているのは、yupとzodの2つのようです。
バリデーションロジックを宣言的に書け、どちらもTypeScriptで実装されているという点では共通しています。
今最も勢いがあるのはzodで、npm trendsを見てもその伸びは一目瞭然です。
yupと比較してみると、以下のような違いがあります。
- zod
- 初めからTypeScriptで実装されており、型推論が強い
- ドキュメントが充実している
- スポンサーが多い
- 多機能
- yup
- 長く使われてきた実績がある
- Hook Form登場以前はFormik + yupがデファクトスタンダードになっていた
- 機能面でzodよりも劣る分、シンプル
- 長く使われてきた実績がある
上記で比較すると、zodのほうがええやん!と思いましたが、今回はyupを選択しました。
理由1: yupのほうが扱いやすい
yupのほうがzodよりも扱いやすい印象でした。
例えばoptionalな値をバリデーションするときに、yupとzodでは以下の書き方の違いがあります[5]。
const yupVersion = yup.object({
email: yup.string().email('メールアドレスの形式ではありません'),
});
const zodVersion = z.object({
email: z.optional({
z.string().email({ message: 'メールアドレスの形式ではありません'})
}).or(z.literal('')),
});
見るからにyupのほうが書きやすいです。
こういった扱いやすさの点の比較は、僕よりも先にきれいにまとめている方がおりましたので、興味があればこちらを見てみてください。
yupは型の堅牢性がzodに比べると弱い印象ですが、フォームという性質上、厳密に型がつけられないものも多いため、そこまで堅牢な型システムは不要かな、と思ったのもあります。
理由2: 必要な情報にすぐリーチできる
zodは勢いのある新進気鋭なライブラリという印象ですが、その理由の一つに、大きなエコシステムがあります。
公式ドキュメントのecosystemsをみると、他のライブラリとのインテグレーションが多数記載されています。
中でも、tRPC(クライアントとサーバ間で型情報を共有できる仕組み)という流行りのフレームワークではMUSTとなるそうで、tRPCの公式でもzodを利用した例が記載されています。
そういうわけもあってか、zodの公式ドキュメントは充実している一方で、かなり量があります。また、インターネットの情報量が多い分、必要な情報にたどり着くまでに時間がかかってしまいます。
一方、yupはgithubリポジトリのREADMEを見れば実装に困ることはありませんでした。大体cmd+fでREADMEを検索すれば必要な情報が手に入ります。
また、Reactでは有名な同人誌のりあクト!や、WEB+DB PRESS(発刊休止悲しい)で解説されていたりと、書籍での学習も容易です。
開発メンバーの負担を考えると、学習のしやすさは大事なポイントだと思っています。
もちろん、zodのほうが人気でスポンサーも多くついているところは重要な要素です。
しかし、React Hook Formのresolverとして使うには、「必要な情報にリーチしやすいか」「扱いやすいか」というところでyupに軍配が上がりました。
導入した後が大事!!
せっかくライブラリを導入しても、使われなくては意味がありません。
導入したあとで、モブプロを開催したりドキュメントを作ったりと、少しでも知見を広げる取り組みを行っています。
メンバーに使ってもらうまでが導入なので、できる限り知見を広げる取り組みをやったほうが良いでしょう。
まとめ
今回、ライブラリ選定で着目すべき観点を3つ挙げました。
- 継続してメンテナンスされそうか
- 必要な情報にリーチしやすいか
- 扱いやすいか
これ以外にも、組織固有の事情やタイミングなど様々な要素があると思います。
すべての観点の根底にあるのは、その選択がプロダクトを成長させ続けられるかということです。
そして、メンバーへの展開もお忘れなく。
最後に|選択に正解はない
技術の進歩によって、外部環境がどのように変化するかは誰にもわかりません。
今絶賛される選択が数年後はそうでなくなっているかもしれませんし、開発元の企業が倒産する、なんてこともあるかもしれません。
そんな時代にできるのは、少しでも成功確率の高い選択をするしかないのです。
僕の取った選択が数年後正解になっているかはわかりませんが、良い結果になることを願っています。
Discussion
React Hook Formをvercelが開発してるって出典はどこでしょうか?
ご指摘ありがとうございます!僕の勘違いでした(SWRと間違えてました)。
記事を修正いたしました。誤解を招きすみません。
ご参考までに、ZodもドキュメントはREADME一枚になっていると思います。
ご指摘ありがとうございます!
以下を見ていましたが、これがREADMEと同じなんですね。
補足ですが、ここで言いたいのはREADME一枚になっていることではなく、必要な情報が少ないということでした。適切な表現に修正しました。