0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Conformとshadcn-uiのSelectコンポーネントで起きた動作不良を解決!

Last updated at Posted at 2025-05-14

発生した問題

conformのuseFormを用いてフォームを管理する際、セレクトコンポーネント(Shadcn UI/Radix UIベース)の選択状態が正しく反映されない問題が発生しました。具体的には次のような状況です:

  1. セレクトボックスで値を選択する
  2. 別の値を選択しようとする
  3. UIには最初に選択した値が表示されたままになる

原因

調べてみた感じ、以下の問題っぽかったです。

  1. イベント発火の問題
    • Conformはネイティブフォームイベント(input、change、blur)を監視して状態を管理している
    • カスタムUIコンポーネントはこれらのイベントを自動的に発火しない

解決策

(例):

export const ExampleSelect: React.FC<ExampleSelectProps> = ({
  options,
  placeholder = "選択してください",
  label,
  meta,
}) => {
  const control = useInputControl(meta);
  const id = useId();

  const handleValueChange = (selectedValue: string) => {
    if (selectedValue === "_blank" || selectedValue === "") {
      control.change(undefined);
    } else {
      control.change(selectedValue);
    }
    // フォーカスとブラーイベントを明示的に発火
    control.focus();
    control.blur();
  };

  // control.valueを使用して現在の値を取得
  const currentValue = control.value ?? "";

  return (
    <div className="flex items-center gap-2">
      {/* ... */}
      <Select
        name={meta.name}
        value={currentValue}
        onValueChange={handleValueChange}
      >
        {/* ... */}
      </Select>
    </div>
  );
};

重要なポイント

  1. useInputControlフックの活用

    • Conformが提供するuseInputControlフックを使用して入力制御を行う
    • control.valueを参照することで常に最新の値を取得
  2. イベントの明示的な発火

    • control.change():値を更新し、changeとinputイベントを発火
    • control.focus():focusとfocusinイベントを発火
    • control.blur():blurとfocusoutイベントを発火
  3. イベントの順序

    • 値の変更後にfocus()blur()の順で呼び出すことで、Conformに状態変更を確実に通知

なぜこれで解決したのか

shadcn-uiはネイティブHTML要素とは異なり、ブラウザの標準的なフォームイベントを自動的にしないみたいです。

Conformはこれらのイベントを監視して状態を管理しているため、明示的にイベントを発火させる必要があります。

control.focus()control.blur()を連続して呼び出すことで、Conformに「このフィールドにフォーカスが当たり、その後フォーカスが外れた」ことを通知します。これにより、Conformは内部状態を更新し、UIに反映させることができます。

参考資料

まとめ

shadcn-uiとConformを統合する際は、以下の点に注意する必要がありそうです:

  1. useInputControlフックを使用して入力制御を行う
  2. 値の変更時にイベントを明示的に発火させる
  3. 値の参照にはcontrol.valueを使用する
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?