Blog

react-hook-formのuseFormContextでuseFormメソッドを受け渡す

react-hook-formは、React16.8.0から導入されたフォームのライブラリです。
バリデーションかけたあと、それを突破したデータを取得することができます。

最近やっと使い慣れてきた感があるのですが、useFormContextを知って、「気が利く…!」と思ったので記事書こうと思いました。

「作成画面」と「編集画面」のコンポーネントを共通にできる

つまりはこういうことがやりたかったです。
何かを登録する管理画面があるとして、作成画面と編集画面はほぼ同じレイアウトで同じ項目になることが多い。

なので、Next.jsを使ってる時は同じコンポーネントをあてるわけですが、
この時にreact-hook-formをどう使っていいのかわからない。

それぞれのCreateのページテンプレート、Editのページテンプレートがあり、
submitの処理はそれぞれ違う処理になるので、各ページテンプレートで行いたい。

しかし、ここで問題が発生。submitの時にフォームからのデータを受け取る必要がありますが、フォームはフォームコンポーネント(子)なので、親子でやり取りが必要になります。
react-hook-formのuseFormの基本的な使い方が下記ですが、

const { register, handleSubmit, control } = useForm();

フォームのデータを受け取るためには、useFormから得られるメソッドのうち、
handleSubmitやsetValueがページテンプレート側に必要。
でも、controlやregister、watchなどは、フォームコンポーネントで使うので、なんとかして渡す必要があります。

propsで渡そうとしたら大変だった(できなかった)

TypeScriptの型定義が大変でした(結局できませんでした)。
型を調べていくと、ControlとかUseFormRegisterなど、型をインポートすることは可能です。
でも、それを指定してみたところで、TFieldValuesがないとか何かしらのエラーが出ます。
そもそも何か無理があるような気がしました。

useFormContext

useFormContextで、propsでuseFormメソッドを直接わたさずとも、メソッドにアクセスすることができます。

<公式>
https://react-hook-form.com/api/useformcontext

1、親コンポーネントでuseFormし、全てのuseFormメソッドを取得。その中から親コンポーネントで使うものだけ親で定義する。

import { FormProvider, useForm } from "react-hook-form";

const useFormMethods = useForm<FormProps>();
const { setValue, handleSubmit } = useFormMethods;

2、FormProviderをインポートし(1でやった)、useFormの影響範囲をFormProviderでかこむ。その時1のuseFormメソッドを渡す。

<FormProvider {...useFormMethods}>
  <form onSubmit={handleSubmit(onSubmit)}>
    <UserForm />
    <Button>保存する</Button>
  </form>
</FormProvider>

3、子コンポーネントでは、useFormContextでcontrolなどの使いたいuseFormメソッドにアクセスする。

import { useFormContext } from "react-hook-form";

〜〜

  const {
    register,
    control,
    formState: { errors },
  } = useFormContext();

これで、親コンポーネントで定義したuseFormメソッドを、子のフォームコンポーネントで使うことができます。
なおかつ、setValueで初期値を入れる作業が、新規作成画面と編集画面でそれぞれでき、
onSubmitもそれぞれのテンプレートに書くことができます。

おすすめの記事 recommend blog

新着 new blog

github