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

# [What should the default form library be in Blitz apps?](https://github.com/blitz-js/blitz/discussions/768)

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

- [formik](https://github.com/formium/formik)
- [react-final-form](https://final-form.org/react)
- [react-hook-form](https://react-hook-form.com/)

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


# 最初のコメント
Blitz.jsの作者であるBrandon([@flybayer](https://twitter.com/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しなくてはいけない。

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

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

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


### refの渡し方が不自然

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

```tsx
  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.0](https://github.com/react-hook-form/react-hook-form/releases/tag/v6.13.0)で`useController`というhooksが追加されました。それを使えば`<Controller>`で囲って`Render prop`を使うという必要がなくなります。Material UIのコンポーネントなどを使う場合は`<Controller>`を使うしかありませんが，自作のコンポーネントを使う場合は`useController`が使えます！

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