আগের পর্বে আমরা List Rendering শিখেছিলাম, ইতিমধ্যে ইনপুট থেকে onChange দিয়ে ডেটা নিয়েছিও। এই পর্ব থেকে শুরু হচ্ছে "ফর্ম ও ডেটা হ্যান্ডলিং" — প্রথম টপিক Controlled Component, যেখানে আমরা দেখব কীভাবে ফর্ম ইনপুট সম্পূর্ণভাবে React দিয়ে নিয়ন্ত্রণ করা হয়।
Controlled বনাম Uncontrolled — পার্থক্য কী?
Advanced HTML সিরিজে আমরা vanilla JS দিয়ে ফর্ম বানিয়েছিলাম — ইনপুট তার নিজের ভেতরেই ভ্যালু "মনে রাখত", আমরা শুধু দরকার হলে .value দিয়ে পড়তাম। এটাকে বলে Uncontrolled — DOM নিজেই ডেটার "মালিক"।
React-এ সাধারণত Controlled Component প্যাটার্ন ব্যবহার হয় — ইনপুটের ভ্যালু DOM-এ না থেকে React state-এ থাকে, আর ইনপুট শুধু সেই state-এর একটা "প্রতিফলন" দেখায়।
| বৈশিষ্ট্য | Uncontrolled (vanilla JS স্টাইল) | Controlled (React স্টাইল) |
|---|---|---|
| ডেটার "মালিক" | DOM এলিমেন্ট নিজেই | React state |
| বর্তমান মান জানতে | input.value দিয়ে "পড়তে" হয় |
state ভ্যারিয়েবলেই সবসময় থাকে |
| রিয়েল-টাইম ভ্যালিডেশন | প্রতিবার ম্যানুয়ালি পড়ে চেক করতে হয় | সহজ — state পাল্টালেই React re-render করে |
Controlled Input বানানো
দুটো জিনিস লাগবে — value অ্যাট্রিবিউট state থেকে বসানো, আর onChange দিয়ে সেই state আপডেট করা।
function NameInput() {
const [name, setName] = React.useState("");
return (
<input
value={name} // ইনপুট সবসময় state-এর মান দেখাবে
onChange={(e) => setName(e.target.value)} // টাইপ করলেই state আপডেট
/>
);
}
এই দুটো লাইন একসাথে একটা "লুপ" তৈরি করে — value ইনপুটকে বলে কী দেখাতে হবে, onChange React-কে বলে ব্যবহারকারী কী টাইপ করলো। এই দুটো একসাথে না থাকলে ইনপুট "রিড-অনলি" হয়ে যাবে (টাইপ করা যাবে না) — এটা একটা সাধারণ শুরুর দিকের বাগ।
// ❌ ভুল — শুধু value দেওয়া হয়েছে, onChange নেই
// এতে ইনপুটে টাইপ করা যাবে না!
<input value={name} />
// ✅ ঠিক — দুটোই একসাথে
<input value={name} onChange={(e) => setName(e.target.value)} />
কেন Controlled Component ব্যবহার করব?
- রিয়েল-টাইম ভ্যালিডেশন — টাইপ করার সাথে সাথেই চেক করা যায় (যেমন পাসওয়ার্ডের দৈর্ঘ্য)
- কন্ডিশনাল লজিক — ইনপুটের মান অনুযায়ী অন্য UI পাল্টানো সহজ
- ফরম্যাটিং — টাইপ করার সাথে সাথে ফরম্যাট করা যায় (যেমন ফোন নম্বরে ড্যাশ বসানো)
- একই জায়গায় সোর্স অফ ট্রুথ — DOM খুঁজে বেড়াতে হয় না, সব state-এ আছে
বিভিন্ন ইনপুট টাইপ — checkbox, select, textarea
প্রতিটা ইনপুট টাইপের জন্য একটু ভিন্ন অ্যাট্রিবিউট লাগে:
function FormExample() {
const [text, setText] = React.useState("");
const [isChecked, setIsChecked] = React.useState(false);
const [selectedOption, setSelectedOption] = React.useState("html");
const [description, setDescription] = React.useState("");
return (
<div>
{/* সাধারণ টেক্সট ইনপুট */}
<input value={text} onChange={(e) => setText(e.target.value)} />
{/* checkbox — value না, checked ব্যবহার হয় */}
<input
type="checkbox"
checked={isChecked}
onChange={(e) => setIsChecked(e.target.checked)}
/>
{/* select ড্রপডাউন */}
<select value={selectedOption} onChange={(e) => setSelectedOption(e.target.value)}>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
</select>
{/* textarea — HTML-এর মতো ভেতরে টেক্সট না, value অ্যাট্রিবিউট দিয়ে */}
<textarea value={description} onChange={(e) => setDescription(e.target.value)} />
</div>
);
}
গুরুত্বপূর্ণ: checkbox-এ value না, checked ব্যবহার হয়, আর মান পড়তে হয় e.target.checked দিয়ে (e.target.value না)।
লাইভ ডেমো — বিভিন্ন Controlled ইনপুট
নিচে টেক্সট, checkbox, select, আর textarea — চারটাই React state দিয়ে নিয়ন্ত্রিত, প্রতিটার বর্তমান মান নিচে সরাসরি দেখানো হচ্ছে।
রিয়েল-টাইম ভ্যালিডেশনের একটা ঝলক
Controlled Component-এর আসল শক্তি দেখা যায় যখন টাইপ করার সাথে সাথে কিছু চেক করতে হয় — এটা পরের পর্বে (Form Validation) বিস্তারিত দেখব, কিন্তু একটা ছোট উদাহরণ এখনই দেখা যাক।
function PasswordInput() {
const [password, setPassword] = React.useState("");
const isStrong = password.length >= 8;
return (
<div>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<p style={{ color: isStrong ? "green" : "red" }}>
{isStrong ? "✅ যথেষ্ট শক্তিশালী" : "⚠️ কমপক্ষে ৮ অক্ষর দরকার"}
</p>
</div>
);
}
এটা সম্ভব হচ্ছে শুধু এই কারণেই যে password এখন React state-এ আছে — প্রতিবার টাইপ করলেই component re-render হয়ে নতুন করে isStrong হিসাব করে, কোনো ম্যানুয়াল event listener ছাড়াই।
একটা সম্পূর্ণ উদাহরণ — লাইভ প্রিভিউ ফর্ম
চলো একটা ফর্ম বানাই যেখানে টাইপ করার সাথে সাথে নিচে একটা লাইভ প্রিভিউ কার্ড দেখা যাবে — ঠিক যেমনটা আমরা ArifStack-এর SEO meta description লেখার সময় "১৪০ অক্ষর" গুনে দেখি, এটা তারই একটা বাস্তব উদাহরণ।
function PostPreview() {
const [title, setTitle] = React.useState("");
const [description, setDescription] = React.useState("");
return (
<div>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="পোস্টের শিরোনাম"
/>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="মেটা বর্ণনা"
/>
<p>অক্ষর সংখ্যা: {description.length} / 160</p>
{/* লাইভ প্রিভিউ */}
<div className="preview-card">
<h3>{title || "শিরোনাম এখানে দেখা যাবে"}</h3>
<p>{description || "বর্ণনা এখানে দেখা যাবে"}</p>
</div>
</div>
);
}
এখানে title || "..." — যদি title খালি স্ট্রিং হয় (falsy), ডিফল্ট প্লেসহোল্ডার টেক্সট দেখাবে। এটাই Controlled Component-এর আসল শক্তি — একটা মাত্র state ভ্যারিয়েবল দিয়ে ইনপুট, ক্যারেক্টার কাউন্ট, আর লাইভ প্রিভিউ — সবকিছু সিঙ্কে থাকছে।
নিজে চেষ্টা করো
Exercise:
- উপরের
PasswordInputcomponent বানাও, তারপর শর্ত যোগ করো — কমপক্ষে একটা সংখ্যা থাকতে হবে। - একটা
selectড্রপডাউন বানাও যেখানে বাছাই করা মান অনুযায়ী নিচে ভিন্ন মেসেজ দেখাবে (Conditional Rendering মনে আছে?)। - উপরের
PostPreviewcomponent নিজে বানাও, নিজের ব্লগের কোনো পোস্টের শিরোনাম-বর্ণনা দিয়ে টেস্ট করো। - একটা টেক্সট ইনপুট বানাও ইচ্ছাকৃতভাবে শুধু
valueদিয়ে,onChangeছাড়া — দেখো কী হয়, তারপর ঠিক করো।
পরের পর্বে যা থাকছে
পরের পর্বে আমরা শিখব একাধিক ফর্ম ইনপুট একসাথে হ্যান্ডল করা — প্রতিটা ইনপুটের জন্য আলাদা useState না লিখে, একটা single state object দিয়ে কীভাবে পুরো ফর্ম পরিচালনা করা যায়।