waiting-listのブログ

placeof - プレイスオブ の開発ブログです

placeofのスペック詳細フォームの実装について

shadcn/uiを使ったサジェストフォームのサンプルとして下記のようなものがあります。 https://www.armand-salle.fr/post/autocomplete-select-shadcn-ui 

運営されているarmandさんのgithubのソースコード

placeof - プレイスオブの物件スペックを入力する画面では、このサンプルにreact-hook-formやzodを使った実装をしています。

suggestのロジックの変更

上記実装で使われている、shadcn/uiのComboboxcmdkのComboboxをwrapしたものです。suggestのロジックを変更したかった(+日本語だと上手くいかない気がした)ので、cmdkのドキュメントに記載されている通りfilterに独自実装を追加してます。sortとかも出来るようです。 https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L88 を下記のようにします

<CommandPrimitive
  filter={(value, search) => {
    if (value.includes(search)) return 1
    return 0
  }}
...
/>

keyの値でvalueのバリデーションをする

keyの追加時の処理

keyとvalueの2つのフォームがあり、keyの値でvalueの値をvalidationする必要するときの実装です。suggestをするkeyがhandleKeyDownなどで確定するときに、onValueChangeで親のComponentの関数を呼び出していますが、そのときに、

 onValueChange={(key: SuggestKey) => {
    form.setValue("suggestKeyId", key.suggestKeyId)
    form.setValue("suggestValueType", key.valueType)
}}

のようにreact-hook-formのsetValue関数を使い、確定したkeyをformに追加します。なお、このときに下記のようにreact-hook-formのformが定義されています。

  type Inputs = z.infer<typeof SuggestKeyFormSchema>
  const form = useForm<Inputs>({
    resolver: zodResolver(SuggestKeyFormSchema),
    defaultValues: defaultValues,
  })

valueの追加時の処理

下記のようにvalueをregisterします。

    <FormItem>
      <FormControl>
        {specKey?.valueType === SpecValueType.TEXTAREA ? ((
          <Input
            aria-invalid={!!form.formState.errors.value}
            {...form.register("value")}
          />
        )}
      </FormControl>
    </FormItem>

そして、下記のようにzodのsuperRefineを使ってvalidateします。このときkeyを追加したときのvalueTypeが使われます。

export const SuggestKeyFormSchema = z
  .object({
    suggestKeyId: z.string().min(1),
    valueType: SuggestValueTypeSchema,
    value: z.string().min(1),
  })
  .superRefine((values, ctx) => {
    if (
      values.valueType === SuggestValueTypeSchema.STRING &&
      values.value.length >= 20
    ) {
      ctx.addIssue({
        message: "need to be less than 20 words",
        code: z.ZodIssueCode.custom,
        path: ["value"],
      })
    }

   ....
  })

i18n

ちなみに、keyはi18nのファイルを参照するようにして表示しています。

suggest一覧の変換箇所 https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L36

確定したkeyの変換箇所 https://github.com/armandsalle/my-site/blob/main/src/components/autocomplete.tsx#L128

詳しくは下記のzenn記事にあります。 i18n一般 https://zenn.dev/k0kishima/articles/956ba3f3dc9629  

zodのi18n https://zenn.dev/aiji42/articles/171f26af4e5b5c

サーバーからデータを取得

サーバーからデータを取得する場合は、こちらのzenn記事が参考になるかと思います https://zenn.dev/mktu/articles/2f9166374d09a0

まとめ

マスターデータをまだそこまで用意できていないのですが、もっと完成度を高めて物件のありとあらゆるスペックが入力できるフォームにしていきたいと考えています。