nino

      Form

      最終更新: 2023年11月28日

      離脱ガードの注意点

      元々 Pages Router に存在した router.events が App Router から使えなくなった ので、ブラウザ標準のクリックイベントリスナーを使って離脱ガードを実装しています。将来的に router.events が復活したらそちらを使ってルーティングのキャンセルを行います。

      "use client";
       
      import * as z from "zod";
      import { zodResolver } from "@hookform/resolvers/zod";
      import { useForm } from "react-hook-form";
      import { Button } from "@/app/components/ui/button";
      import {
        Form,
        FormControl,
        FormField,
        FormItem,
        FormLabel,
        FormMessage,
      } from "@/app/components/ui/form";
      import { Input } from "@/app/components/ui/input";
      import { useI18n } from "@/locales/client";
      import { useToast } from "@/app/components/ui/use-toast";
      import { useFormGuard } from "@/app/lib/form-guard";
       
      export default function FormWidget() {
        const t = useI18n();
        const formSchema = z.object({
          nickname: z
            .string()
            .min(1, {
              message: t("formErrorMessages.required"),
            })
            .max(60, {
              message: t("formErrorMessages.maxLength#othre", {
                count: 60,
              }),
            }),
          email: z
            .string()
            .min(1, {
              message: t("formErrorMessages.required"),
            })
            .email({
              message: t("formErrorMessages.invalid"),
            }),
        });
        const { toast } = useToast();
        const form = useForm<z.infer<typeof formSchema>>({
          mode: "onChange",
          resolver: zodResolver(formSchema),
          defaultValues: {
            nickname: "",
            email: "",
          },
        });
       
        const onSubmit = async (values: z.infer<typeof formSchema>) => {
          return new Promise((resolve) => setTimeout(resolve, 2000)).then(() => {
            form.reset();
            toast({
              title: t("submitted"),
            });
          });
        };
       
        useFormGuard(form.formState.isDirty);
       
        return (
          <>
            <div className="py-6">
              <Form {...form}>
                <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
                  <FormField
                    control={form.control}
                    name="nickname"
                    render={({ field }) => (
                      <FormItem>
                        <FormLabel>{t("nickname")}</FormLabel>
                        <FormControl>
                          <Input
                            type="text"
                            autoComplete="off"
                            placeholder=""
                            {...field}
                          />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />
                  <FormField
                    control={form.control}
                    name="email"
                    render={({ field }) => (
                      <FormItem>
                        <FormLabel>{t("email")}</FormLabel>
                        <FormControl>
                          <Input
                            type="email"
                            autoComplete="email"
                            placeholder=""
                            {...field}
                          />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />
                  <Button
                    disabled={form.formState.isSubmitting || !form.formState.isValid}
                    type="submit"
                  >
                    {t("send")}
                  </Button>
                </form>
              </Form>
            </div>
          </>
        );
      }