React / React Hook Form

React Hook Form

Маягт (form) бол вэб аппын хамгийн нийтлэг хэсэг — нэвтрэх, бүртгүүлэх, захиалга өгөх гэх мэт. React-д маягт гараар зохицуулах нь их код шаарддаг. React Hook Form нь validation, error message, submit логик зэрэг бүхнийг хэд дахин хялбар болгодог хамгийн алдартай library. Эхлэхэд хялбар, дэвшилтэт хэрэглээ ч байдаг!

Суулгах

bash
npm install react-hook-form

Үндсэн хэрэглээ

useForm hook нь маягтын бүх логикийг агуулдаг:

jsx
import { useForm } from "react-hook-form";

function LoginForm() {
  const {
    register, // input-уудыг бүртгэх
    handleSubmit, // submit зохицуулах
    formState: { errors, isSubmitting }, // validation алдаа, submit байдал
  } = useForm();

  async function onSubmit(data) {
    // data нь { email: "...", password: "..." } байна
    console.log("Нэвтрэх мэдээлэл:", data);
    await new Promise((r) => setTimeout(r, 1000)); // API дуудах дуурайлт
  }

  return (
    <form
      onSubmit={handleSubmit(onSubmit)}
      style={{
        display: "flex",
        flexDirection: "column",
        gap: "16px",
        maxWidth: "360px",
      }}
    >
      <div>
        <label>И-мэйл</label>
        <input
          type="email"
          // register нь validation дүрмүүдийг тодорхойлно
          {...register("email", {
            required: "И-мэйл оруулна уу",
            pattern: {
              value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
              message: "Зөв и-мэйл хаяг оруулна уу",
            },
          })}
          style={{
            border: errors.email ? "1px solid red" : "1px solid #ccc",
            padding: "8px",
            width: "100%",
          }}
        />
        {/* Validation алдаа */}
        {errors.email && (
          <p style={{ color: "red", fontSize: "14px" }}>
            {errors.email.message}
          </p>
        )}
      </div>

      <div>
        <label>Нууц үг</label>
        <input
          type="password"
          {...register("password", {
            required: "Нууц үг оруулна уу",
            minLength: {
              value: 8,
              message: "Нууц үг 8-аас дээш тэмдэгт байх ёстой",
            },
          })}
          style={{
            border: errors.password ? "1px solid red" : "1px solid #ccc",
            padding: "8px",
            width: "100%",
          }}
        />
        {errors.password && (
          <p style={{ color: "red", fontSize: "14px" }}>
            {errors.password.message}
          </p>
        )}
      </div>

      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? "Нэвтэрч байна..." : "Нэвтрэх"}
      </button>
    </form>
  );
}

register("email", { ... }) нь input-г маягтад бүртгэж, validation дүрмүүдийг тохируулна. handleSubmit нь validation амжилттай болсны дараа л onSubmit-ийг дуудна.

Бүртгэлийн маягт — дэлгэрэнгүй validation

jsx
import { useForm } from "react-hook-form";

function RegisterForm() {
  const {
    register,
    handleSubmit,
    watch, // талбарын утгыг ажиглах
    formState: { errors, isSubmitting, isSubmitSuccessful },
  } = useForm({ mode: "onBlur" }); // talbar-аас гарахад validation ажиллана

  // password талбарын утгыг ажигладаг — confirm-тэй харьцуулахад хэрэгтэй
  const password = watch("password");

  async function onSubmit(data) {
    await fetch("/api/register", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });
  }

  if (isSubmitSuccessful) {
    return <p style={{ color: "green" }}>Бүртгэл амжилттай боллоо! 🎉</p>;
  }

  return (
    <form
      onSubmit={handleSubmit(onSubmit)}
      style={{
        display: "flex",
        flexDirection: "column",
        gap: "12px",
        maxWidth: "400px",
      }}
    >
      <div>
        <label>Нэр</label>
        <input
          {...register("name", {
            required: "Нэр оруулна уу",
            minLength: {
              value: 2,
              message: "Нэр 2-оос дээш тэмдэгт байх ёстой",
            },
          })}
        />
        {errors.name && <p style={{ color: "red" }}>{errors.name.message}</p>}
      </div>

      <div>
        <label>И-мэйл</label>
        <input
          type="email"
          {...register("email", {
            required: "И-мэйл оруулна уу",
            pattern: {
              value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
              message: "Буруу и-мэйл хаяг",
            },
          })}
        />
        {errors.email && <p style={{ color: "red" }}>{errors.email.message}</p>}
      </div>

      <div>
        <label>Нууц үг</label>
        <input
          type="password"
          {...register("password", {
            required: "Нууц үг оруулна уу",
            minLength: { value: 8, message: "8-аас дээш тэмдэгт байх ёстой" },
          })}
        />
        {errors.password && (
          <p style={{ color: "red" }}>{errors.password.message}</p>
        )}
      </div>

      <div>
        <label>Нууц үг давтах</label>
        <input
          type="password"
          {...register("confirmPassword", {
            required: "Нууц үгийг давтана уу",
            validate: (value) =>
              value === password || "Нууц үг таарахгүй байна",
          })}
        />
        {errors.confirmPassword && (
          <p style={{ color: "red" }}>{errors.confirmPassword.message}</p>
        )}
      </div>

      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? "Бүртгүүлж байна..." : "Бүртгүүлэх"}
      </button>
    </form>
  );
}

validate функц нь custom validation дүрэм — утга буцаавал тухайн утга нь алдааны мэдэгдэл болно, true буцаавал validation амжилтай гэсэн үг.

useFormState ба нарийн тохиргоо

jsx
import { useForm, Controller } from "react-hook-form";

// Controller нь custom input component-уудтай ажиллахад хэрэгтэй
function AdvancedForm() {
  const {
    register,
    handleSubmit,
    control, // Controller-д дамжуулна
    reset, // маягтыг анхны утганд нь буцаах
    setValue, // программаар утга тавих
    formState: { errors, isDirty, isValid },
  } = useForm({
    defaultValues: {
      name: "",
      role: "student",
    },
    mode: "onChange", // бичих болгонд validation
  });

  function onSubmit(data) {
    console.log(data);
    reset(); // submit-н дараа маягтыг цэвэрлэнэ
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name", { required: "Нэр шаардлагатай" })} />
      {errors.name && <p style={{ color: "red" }}>{errors.name.message}</p>}

      <select {...register("role")}>
        <option value="student">Суралцагч</option>
        <option value="teacher">Багш</option>
        <option value="admin">Админ</option>
      </select>

      {/* isDirty — маягт өөрчлөгдсөн эсэх */}
      {/* isValid — бүх validation давсан эсэх */}
      <button type="submit" disabled={!isDirty || !isValid}>
        Хадгалах
      </button>
    </form>
  );
}

isDirty ба isValid ашиглан submit товчийг зохистой идэвхтэй/идэвхгүй болгож болно — хэрэглэгч юу ч өөрчлөөгүй эсвэл validation алдаатай үед товч disabled байна.

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

Zustand сурна — React-н хялбар бөгөөд хүчирхэг глобал state management library. Redux-аас хавьгүй хялбар, Context-ээс илүү хурдан. Нэг файлд бүх глобал state-г зохион байгуулж чаддаг.