registerで管理している要素にrefを渡した結果

registerで管理している要素にrefを渡した結果

投稿日: 2025年03月05日

学習振り返り
要約
  • React Hook Formのregisterを使ったフォーム要素のref管理で、直接refを渡すと正常に動作しない問題に直面した。
  • textareaに対してregisterを使う際は、分解してrefとイベントハンドラを適切に組み合わせる必要がある。
  • 最終的にuseRefを利用しつつ、watchで取得した値を使いながら、ボタンをクリックで新しいテキストを挿入する実装が成功した。

はじめに

ハマりました🥺
registerを使うことでフォーム要素のrefを介して直接操作できることはなんとなく理解していましたが、実際の実装において別途refを渡してしまうと問題が発生するとは思っていませんでした。
AIも教えてくれなかった。。

私みたいに時間溶かすともったいないので頭の片隅にでも置いておいてください。

register で管理している要素に ref を上書きすると正常に動かない!!

渡してもエラー吐かないから厄介です!!

やりたかったこと

フォーム管理はreact-hook-form、バリデーションはzodを使いました。

ボタンを押すとtextareaの中に採番した番号が加わって、最後にフォーカスするという操作をしたかったです。
useRefをつかってフォーカスすることになるのでrefを渡したかったのですがハマりました。

ダメな例

"use client";
import { useRef } from "react";
import { useAddAritcleForm } from "../_hooks/useAddAritcleForm";
//省略
 const {
    register,
  } = useAddAritcleForm();
const textareaRef = useRef<HTMLTextAreaElement>(null);
//省略
<Textarea
    label="作り方"
    disabled={isSubmitting}
    id="tips"
    placeholder="作り方を入力してください"
    errors={errors.tips}
    {...register("tips")}
  ref={textareaRef}
/>

これNGです。
watch("tips")してもundefinedになって、なんで?え。なんで?(困惑)でした。

結論

工夫が必要です。。
registerをそのまま渡さず、一度分解してuseRefと組み合わせる必要があります。

import { useTextInsert } from "../_hooks/useTextInsert";
import { useAddAritcleForm } from "../_hooks/useAddAritcleForm";

//省略
 const {
    register,
    setValue,
    watch,
  } = useAddAritcleForm();
//useTextInsert内でconst textareaRef = useRef<HTMLTextAreaElement>(null);と宣言している
const { textareaRef, insertText } = useTextInsert({
    value: watch("tips") ?? "",
    setValue: val => setValue("tips", val),
  });
// refは内部管理用、restにはイベントハンドラを含む
const { ref, ...rest } = register("tips");

//省略

<div className="relative">
    <Textarea
         label="作り方"
         disabled={isSubmitting}
         id="tips"
         placeholder="作り方を入力してください"
         errors={errors.tips}
         {...rest} // React-hook-formの管理用props
         ref={e => {
           ref(e); // React-hook-formにrefを渡してフォーム管理を維持
          textareaRef.current = e; //useTextInsertで参照するためのrefを設定
         }}
     />
     <div className="absolute bottom-3 right-1 w-[100px]">
        <Button
          type="button"
          onClick={() => {
           const currentText = watch("tips");
           const lines = currentText ? currentText.split("\n") : [];
           const length = lines.length;
           const newText = `${length > 0 ? "\n" : ""}${length + 1}. `;
           insertText(newText);
          }}
         >
          ➕ 手順
        </Button>
      </div>
     </div>

これでuseRef使えます!!

おわりに

なんでundefined??凡ミスしてる?ハテナが止まらなくて、AIに聞くも答えに行き着かず。
もしや。。。register渡してるのにさらにref渡して重複してるかも・・これ問題ある気がするけどどう?って聞くと「その通りです!こうしたらいいです!」って来るコードも同じこと繰り返しててめっちゃつまらん漫才してるみたいになってました。

AIでコード書ける人が逆にすごいと思う今日この頃です。
結構使えないAI、結局自己解決することばかりです。

コードが長くて省略して過不足ありますがrefの箇所だけみてくださいw
参考になれば。

シェア!

Threads
user
吉本茜
山口在住/二児の母/育休中
Loading...
記事一覧に戻る
Threads
0