Next.js / Server Action + маягт

Server Action + маягт

Өмнөх хичээлд Server Action-г button click дээр дуудах аргыг суралцсан. Энэ хичээлд Server Action-г HTML <form> элементтэй хослуулна. Энэ хослол нь JavaScript ажиллахгүй байсан ч form-г зөв ажилладаг болгодог — веб хөгжүүлэлтийн хамгийн найдвартай загвар.

form action шинж чанар

HTML <form> элементийн action шинж чанарт Server Action шууд дамжуулж болно:

tsx
// app/profile/page.tsx
import { updateUsername } from "@/app/actions";

export default function ProfilePage() {
  return (
    <form action={updateUsername}>
      <label>
        Хэрэглэгчийн нэр
        <input type="text" name="username" required />
      </label>
      <button type="submit">Хадгалах</button>
    </form>
  );
}
typescript
// app/actions.ts
"use server";

import { createClient } from "@/lib/supabase/server";
import { revalidatePath } from "next/cache";

export async function updateUsername(formData: FormData) {
  const username = formData.get("username") as string;

  if (!username || username.length < 3) {
    throw new Error("Хэрэглэгчийн нэр хэт богино байна");
  }

  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) throw new Error("Нэвтрээгүй байна");

  await supabase.from("profiles").update({ username }).eq("id", user.id);

  revalidatePath("/profile");
}

action={updateUsername} гэж бичихэд form submit хийгдэх үед Next.js автоматаар FormDataupdateUsername функцэд дамжуулна.

useActionState — form-н төлөв удирдах

Алдаа харуулах, амжилтын мэдэгдэл гаргах зэрэгт React-н useActionState hook ашигладаг:

tsx
"use client";

import { useActionState } from "react";
import { updateUsername } from "@/app/actions";

interface ActionState {
  error?: string;
  success?: boolean;
}

export default function UsernameForm() {
  const [state, formAction, isPending] = useActionState<ActionState, FormData>(
    async (_prev, formData) => {
      try {
        await updateUsername(formData);
        return { success: true };
      } catch (err) {
        return { error: (err as Error).message };
      }
    },
    {},
  );

  return (
    <form action={formAction}>
      <label>
        Хэрэглэгчийн нэр
        <input type="text" name="username" required />
      </label>

      {state.error && <p style={{ color: "red" }}>{state.error}</p>}
      {state.success && (
        <p style={{ color: "green" }}>Амжилттай хадгалагдлаа!</p>
      )}

      <button type="submit" disabled={isPending}>
        {isPending ? "Хадгалж байна..." : "Хадгалах"}
      </button>
    </form>
  );
}

useActionState гурван зүйл буцаана:

  • state — өмнөх action-н үр дүн (алдаа эсвэл амжилт)
  • formAction — form-н action шинж чанарт өгөх функц
  • isPending — action одоо ажиллаж байгаа эсэх

useFormStatus — submit товч

useFormStatus hook нь form дотор submit-н төлөвийг мэдэхэд хэрэглэнэ. Тусдаа component болгон гаргах нь ухаалаг:

tsx
"use client";

import { useFormStatus } from "react-dom";

export function SubmitButton({ label }: { label: string }) {
  const { pending } = useFormStatus();

  return (
    <button type="submit" disabled={pending}>
      {pending ? "Хадгалж байна..." : label}
    </button>
  );
}
tsx
// UsernameForm дотор ашиглах
import { SubmitButton } from "@/components/ui/SubmitButton";

<form action={formAction}>
  <input type="text" name="username" required />
  <SubmitButton label="Хадгалах" />
</form>;

SubmitButton-г хаана ч ашиглаж болно — useFormStatus автоматаар ойрын form-н төлөвийг мэдэрдэг.

Дараагийн хичээлд:

API Route Handler бичиж сурна. Гадны сервис, webhook, mobile app-тай холбоход хэрэгтэй REST endpoint хэрхэн үүсгэхийг ойлгоно.