আগের পর্বে আমরা একটা 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:
- উপরের সাইনআপ ফর্মে
confirmPasswordফিল্ড যোগ করো, যেটাpassword-এর সাথে না মিললে এরর দেখাবে। - উপরের লাইভ ডেমোর মতো একটা ফর্ম বানাও, কিন্তু ইমেইল ফিল্ডে "@" ছাড়াও ডোমেইনে "." আছে কিনা চেক করো।
isSubmittingস্টেট যোগ করো, সাবমিট বাটনেdisabledঅ্যাট্রিবিউট আর "সাবমিট হচ্ছে..." টেক্সট দেখাও।- validation লজিকটা একটা আলাদা ফাংশনে বের করে নিয়ে যাও, component-এর ভেতরে শুধু সেটা কল করো।
পরের পর্বে যা থাকছে
ফর্ম ও ডেটা হ্যান্ডলিং অংশ শেষ হলো। পরের পর্ব থেকে শুরু হবে "Component যোগাযোগ ও Lifecycle" — প্রথম টপিক useEffect Hook বেসিক, যেখানে আমরা শিখব একটা component কখন "mount" হয়, আর dependency array কীভাবে কাজ করে।