1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChakraUIとConformでフォームを作る2

Last updated at Posted at 2024-11-23

話としてはこれの続きです
https://qiita.com/stopod/items/42ac91a67037e849e97f

目標

  • もっと簡単にFormを作成したい

実際のソースコード

画面は以前の記事から変わっていません
image.png

やったこと

だいたいはこのPRに込められてます

課題点はここです

home.tsx
<ConfromField
 label=""
 required
 id={fields.lastName.id}
 errorId={fields.lastName.errorId}
 errorText={fields.lastName.errors}
 invalid={!!fields.lastName.errors?.length}
>
    <Input
     placeholder=""
     variant="outline"
     {...getInputProps(fields.lastName, { type: "text" })}
    />
</ConfromField>

これをこうしました

home.tsx
<FormFieldText
 label=""
 inputProps={{
     ...getInputTypeTextProps(fields.lastName),
 }}
/>

Conformに用意されているヘルパーからだとerrorId, errorText等が取得できず、個別で受け取る必要がありました
また、FieldComponentとInputComponentでそれぞれ必要なものがあるのでまとめて、ヘルパーからまとめて渡すことができませんでした

なので以下のようにしました

  • FiledとInputをまとめたform-filed-textというcomponentを作成
  • ヘルパー関数をラップしたものを作成

それがこれです

form-field-text/index.tsx
import { Input, InputProps } from "@chakra-ui/react";
import { ConfromField, ConfromFieldProps } from "../ui/field";
import { FieldMetadata, getInputProps } from "@conform-to/react";
import { ReactNode } from "react";

type FormFiledTextProps = ConfromFieldProps & {
  inputProps?: InputProps & {
    errorId?: string;
    errorText?: ReactNode;
    invalid?: boolean;
  };
};

export const FormFieldText = (props: FormFiledTextProps) => {
  const { inputProps, ...rest } = props;
  const { id, errorId, errorText, invalid, required, ...inputPropsRest } =
    inputProps || {};

  return (
    <ConfromField
      id={id}
      errorId={errorId}
      errorText={errorText}
      invalid={invalid}
      required={required}
      {...rest}
    >
      <Input id={id} {...inputPropsRest} />
    </ConfromField>
  );
};

export const getInputTypeTextProps = (metadata: FieldMetadata) => {
  const errorId = metadata.errorId;
  const errorText = metadata.errors;
  const invalid = !metadata.valid;
  return {
    errorId,
    errorText,
    invalid,
    ...getInputProps(metadata, { type: "text" }),
  };
};

export const getInputTypeDateProps = (metadata: FieldMetadata) => {
  const errorId = metadata.errorId;
  const errorText = metadata.errors;
  const invalid = !metadata.valid;
  return {
    errorId,
    errorText,
    invalid,
    ...getInputProps(metadata, { type: "date" }),
  };
};

ヘルパー関数としてこれが適切なカスタマイズ方法かがわかりませんが、getInputTypeTextPropsを作成してerrorId, errorText, invalidを付与するようにしました
これをComponent側で分解してFiledとInputにそれぞれ適切に渡します
そうすることで呼び出し側では(基本的には)ヘルパー関数だけで入力フォームが完成します

似たような感じでselect componentも分離してヘルパー関数をラップした関数を作りました
https://github.com/stopod/rr-chakra-conform-sample/commit/e34dcee19c1f0239b85dd0b63bd56764f2d85305#diff-a573f4e9daaa115b6c047848fa5a19015971f432b7f88446c12c60e42300b5f2

終わりに

ついでにReactRouter v7がリリースされたのでv7.0.1にしました
ヘルパー関数の扱いがわからないのと(ググるとこんな適当にカスタマイズしてるのではなくて、ちゃんとなんかもにょもにょしている人がいた)、FieldとInputをまとめたcomponentにおけるpropsのいい感じの扱いがわからない

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?