React এর হাতেখড়ি (পর্ব ৯) — Controlled Component শিখুন

Controlled Component

আগের পর্বে আমরা 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:

  1. উপরের PasswordInput component বানাও, তারপর শর্ত যোগ করো — কমপক্ষে একটা সংখ্যা থাকতে হবে।
  2. একটা select ড্রপডাউন বানাও যেখানে বাছাই করা মান অনুযায়ী নিচে ভিন্ন মেসেজ দেখাবে (Conditional Rendering মনে আছে?)।
  3. উপরের PostPreview component নিজে বানাও, নিজের ব্লগের কোনো পোস্টের শিরোনাম-বর্ণনা দিয়ে টেস্ট করো।
  4. একটা টেক্সট ইনপুট বানাও ইচ্ছাকৃতভাবে শুধু value দিয়ে, onChange ছাড়া — দেখো কী হয়, তারপর ঠিক করো।

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

পরের পর্বে আমরা শিখব একাধিক ফর্ম ইনপুট একসাথে হ্যান্ডল করা — প্রতিটা ইনপুটের জন্য আলাদা useState না লিখে, একটা single state object দিয়ে কীভাবে পুরো ফর্ম পরিচালনা করা যায়।

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

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

যোগাযোগ ফর্ম