Blitz.jsの議論から学ぶ,formik vs react-final-form vs react-hook-form


What should the default form library be in Blitz apps?

BlitzがどのFormライブラリをデフォルトにするかの議論が参考になったので要約しました。

の3択で,結論としては,React Final Formを推奨とする形に落ち着きました。

最初のコメント

Blitz.jsの作者であるBrandon(@flybayer)さんがコメントしています。要約するとこんな感じ。

  • Formik
    以前使ってたけど,パフォーマンスめっちゃ悪いって気づいたから,Formikは無しで。

  • React-final-form
    最近ずっと使ってるけどいい感じ。

  • React-hook-form
    ほとんど使ったことない。

React-final-formをReact-hook-formに書き換えてみたが,コードの複雑さとしてはそこまで差異はない。
https://github.com/blitz-js/blitz/pull/767/files

議論

全体的にFormikは無いよねという感じでした。

気になった意見をpick upします。

react-hook-formのデメリット

対象のコメント→ https://github.com/blitz-js/blitz/discussions/768#discussioncomment-39148

別のFormライブラリとの互換性の低さ

MaterialUIなどのサードパーティー製のコンポーネントと一緒に使う場合は
<Controller>コンポーネントでwrapしなくてはいけない。

      <Controller
        name="iceCreamType"
        as={Select}
        options={[
          { value: "chocolate", label: "Chocolate" },
          { value: "strawberry", label: "Strawberry" },
          { value: "vanilla", label: "Vanilla" }
        ]}
        control={control}
        rules={{ required: true }}
      />

<Controller>を使わないパターンと使うパターンの2つの異なるAPIを知っておかなくてはいけない。

一方,react-final-formはuseField()というAPIだけで済むので,他のライブラリとの互換性が高い。

refの渡し方が不自然

focusしたときに何かを発動したいときなどはrefを自分で渡すことになるが,そのときのrefの渡し方が面倒くさい。

  const { register, handleSubmit } = useForm();
  const firstNameRef = useRef();
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={(e) => {
        register(e)              // hook-form register
        firstNameRef.current = e // manually assign your ref
      }} />

ref={ref}で渡したいのに…。

react-final-formのデメリット

render propsが初心者には難しいのではないか?というコメントがいくつかあった。

  • 基本的にrender propsを使う
    • react-final-form
    • formik
  • 基本的にrender propsを使わない
    • react-hook-form

それに対し,Brandonさんは以下のように反論しています。

there is only one top level render prop with final-form which also provides the form context.

トップ層でしか使用していないし,

So either way, you'll likely have a render prop. I definitely agree the primary API shouldn't be a render prop, but looks like it's impossible to 100% avoid render props.

react-hook-formでも<Controller/>を使ったらrender propsを使うことになるし,render propsから完全に逃れることはできないのではないか?とのことです。

まとめ

今回はReact Final Formを推奨とする結論になりましたが,「とにかく速く開発したいからみんなが使えて学習コストの低いreact hook formで」など,プロジェクトによって吟味する必要がありそうです。

「react-hook-formは広く使われているからみんな慣れてるだろうし良い」というような意見に対して「学習コストが低いものを選定基準にするのではなく,既存のプロジェクトをBlitzに置き換えることになったときになるべく痛みが少ないものを使いたい。」と返していて,ライブラリ選定の参考になる見方だと思いました。

追記

React Hook Formの作者である@bluebill1049さんがコメントしてくださりました。(詳しくは本人のコメントを参照してください!)

2020年12月ごろにリリースされたv6.13.0useControllerというhooksが追加されました。それを使えば<Controller>で囲ってRender propを使うという必要がなくなります。Material UIのコンポーネントなどを使う場合は<Controller>を使うしかありませんが,自作のコンポーネントを使う場合はuseControllerが使えます!

また,refについてもV7ではフォーカス管理を改善していく予定とのことです。