React এর হাতেখড়ি (পর্ব ১১) — Form Validation শিখুন

Form Validation in React

আগের পর্বে আমরা একটা single state object দিয়ে একাধিক ইনপুট সামলেছিলাম। এই পর্বে আমরা সেই ফর্মে Validation যোগ করব — ভুল ইনপুট শনাক্ত করা, ব্যবহারকারীকে জানানো, আর সঠিক submit হ্যান্ডেল করা। এতে আমরা Advanced JS সিরিজের Error Handling ধারণাও React-এ প্রয়োগ করব।

Validation-এর জন্য আরেকটা State — errors

মূল কৌশল হলো — ফর্মের ডেটার পাশাপাশি একটা আলাদা errors object state রাখা, যেখানে প্রতিটা ফিল্ডের এরর মেসেজ (থাকলে) সংরক্ষিত হয়।

function SignupForm() {
  const [formData, setFormData] = React.useState({ email: "", password: "" });
  const [errors, setErrors] = React.useState({}); // খালি অবজেক্ট = কোনো এরর নেই

  // ...
}

errors.email থাকলে সেই ফিল্ডে সমস্যা আছে, না থাকলে ঠিক আছে — এই সাধারণ নিয়মের উপর পুরো validation সিস্টেম দাঁড়িয়ে থাকবে।

Submit-এর সময় Validate করা

সবচেয়ে সাধারণ প্যাটার্ন — যখন ব্যবহারকারী ফর্ম সাবমিট করে, তখন সব ফিল্ড চেক করে errors object বানানো, তারপর কোনো এরর না থাকলেই এগিয়ে যাওয়া।

function validate(formData) {
  const newErrors = {};

  if (!formData.email.trim()) {
    newErrors.email = "ইমেইল আবশ্যক";
  } else if (!formData.email.includes("@")) {
    newErrors.email = "সঠিক ইমেইল দাও";
  }

  if (!formData.password) {
    newErrors.password = "পাসওয়ার্ড আবশ্যক";
  } else if (formData.password.length < 6) {
    newErrors.password = "কমপক্ষে ৬ অক্ষর দরকার";
  }

  return newErrors;
}

function handleSubmit(e) {
  e.preventDefault();
  const newErrors = validate(formData);
  setErrors(newErrors);

  if (Object.keys(newErrors).length === 0) {
    // কোনো এরর নেই, ফর্ম সাবমিট করা যাবে
    console.log("ফর্ম সঠিক, সাবমিট হচ্ছে:", formData);
  } else {
    console.log("ফর্মে এরর আছে", newErrors);
  }
}

Object.keys(newErrors).length === 0 — এটাই চেক করে কোনো এরর আছে কিনা। যদি newErrors খালি থাকে, তার মানে কোনো ফিল্ডে সমস্যা নেই।

এরর মেসেজ দেখানো — Conditional Rendering প্রয়োগ

পর্ব ৭-এ শেখা && এখানে খুব কাজে লাগবে — শুধু এরর থাকলেই মেসেজ দেখানো হবে।

<div>
  <input
    name="email"
    value={formData.email}
    onChange={handleChange}
    style={{ borderColor: errors.email ? "red" : "#ccc" }}
  />
  {errors.email && <p style={{ color: "red", fontSize: "13px" }}>{errors.email}</p>}
</div>

এখানে দুইটা জিনিস একসাথে হচ্ছে — ইনপুটের বর্ডার লাল হয়ে যাচ্ছে (ternary দিয়ে), আর নিচে এরর মেসেজ দেখা যাচ্ছে (&& দিয়ে) — দুটোই errors.email থাকা না থাকার উপর নির্ভর করছে।

টাইপ করার সাথে সাথে এরর সরানো

ভালো UX-এর জন্য — ব্যবহারকারী ভুল ঠিক করা শুরু করলেই এরর মেসেজ সরিয়ে ফেলা ভালো, শুধু আবার submit করা পর্যন্ত অপেক্ষা না করে।

function handleChange(e) {
  const { name, value } = e.target;
  setFormData({ ...formData, [name]: value });

  // এই ফিল্ডে যদি আগে এরর থাকে, টাইপ করা শুরু করলেই সেটা সরিয়ে দাও
  if (errors[name]) {
    const newErrors = { ...errors };
    delete newErrors[name]; // ঐ ফিল্ডের এরর মুছে ফেলা
    setErrors(newErrors);
  }
}

লাইভ ডেমো — একটা সম্পূর্ণ Validation সিস্টেম

নিচের ফর্মে খালি বা ভুল ইমেইল/পাসওয়ার্ড দিয়ে সাবমিট করার চেষ্টা করো — এরর দেখাবে। তারপর টাইপ করা শুরু করলে এরর মিলিয়ে যাবে।

isSubmitting স্টেট — ডাবল সাবমিট আটকানো

ফর্ম সাবমিট হওয়ার সময় (বিশেষ করে API কল করলে) বাটন একাধিকবার চাপা এড়াতে একটা isSubmitting স্টেট রাখা ভালো অভ্যাস — এটা পরের পর্বে useEffect দিয়ে fetch করার সময় খুব কাজে লাগবে।

function SignupForm() {
  const [isSubmitting, setIsSubmitting] = React.useState(false);

  async function handleSubmit(e) {
    e.preventDefault();
    const newErrors = validate(formData);
    setErrors(newErrors);
    if (Object.keys(newErrors).length > 0) return;

    setIsSubmitting(true);
    try {
      // এখানে actual API কল হবে (পরের পর্বে বিস্তারিত)
      await submitForm(formData);
    } catch (error) {
      console.error("সাবমিট ব্যর্থ:", error);
    } finally {
      setIsSubmitting(false); // এরর হোক বা সফল হোক, বাটন আবার সক্রিয় করা
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {/* ইনপুটগুলো */}
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? "সাবমিট হচ্ছে..." : "সাবমিট করো"}
      </button>
    </form>
  );
}

এখানে Advanced JS পর্ব ১০-এর try/catch/finally সরাসরি প্রয়োগ হচ্ছে — finally নিশ্চিত করছে সাবমিট সফল হোক বা ব্যর্থ, বাটন যেন আবার ক্লিকযোগ্য হয়ে যায়।

একটা সম্পূর্ণ উদাহরণ — Validation ফাংশন আলাদা করা

বড় ফর্মে validation লজিক আলাদা ফাংশনে (বা আলাদা ফাইলেও, Advanced JS পর্ব ১১-এর Module প্যাটার্ন মনে আছে?) রাখা ভালো — component-টা পরিষ্কার থাকে।

// validators.js — আলাদা ফাইলে রাখা যায়
export function validateSignupForm(data) {
  const errors = {};

  if (!data.name.trim()) errors.name = "নাম আবশ্যক";
  if (!data.email.includes("@")) errors.email = "সঠিক ইমেইল দাও";
  if (data.password.length < 6) errors.password = "কমপক্ষে ৬ অক্ষর দরকার";
  if (data.password !== data.confirmPassword) {
    errors.confirmPassword = "পাসওয়ার্ড মিলছে না";
  }

  return errors;
}
// SignupForm.jsx
import { validateSignupForm } from "./validators.js";

function SignupForm() {
  // ...
  function handleSubmit(e) {
    e.preventDefault();
    const newErrors = validateSignupForm(formData);
    setErrors(newErrors);
    if (Object.keys(newErrors).length === 0) {
      console.log("সাবমিট হচ্ছে", formData);
    }
  }
  // ...
}

এভাবে validation লজিক component থেকে আলাদা থাকায় — টেস্ট করা সহজ হয়, আর একই validation ফাংশন অন্য component-এও পুনর্ব্যবহার করা যায়।

নিজে চেষ্টা করো

Exercise:

  1. উপরের সাইনআপ ফর্মে confirmPassword ফিল্ড যোগ করো, যেটা password-এর সাথে না মিললে এরর দেখাবে।
  2. উপরের লাইভ ডেমোর মতো একটা ফর্ম বানাও, কিন্তু ইমেইল ফিল্ডে "@" ছাড়াও ডোমেইনে "." আছে কিনা চেক করো।
  3. isSubmitting স্টেট যোগ করো, সাবমিট বাটনে disabled অ্যাট্রিবিউট আর "সাবমিট হচ্ছে..." টেক্সট দেখাও।
  4. validation লজিকটা একটা আলাদা ফাংশনে বের করে নিয়ে যাও, component-এর ভেতরে শুধু সেটা কল করো।

পরের পর্বে যা থাকছে

ফর্ম ও ডেটা হ্যান্ডলিং অংশ শেষ হলো। পরের পর্ব থেকে শুরু হবে "Component যোগাযোগ ও Lifecycle" — প্রথম টপিক useEffect Hook বেসিক, যেখানে আমরা শিখব একটা component কখন "mount" হয়, আর dependency array কীভাবে কাজ করে।

একটি মন্তব্য পোস্ট করুন

নবীনতর পূর্বতন

যোগাযোগ ফর্ম