রিয়্যাক্ট ডিজাইন প্যাটার্ন কেন দরকার? (একটি ১০ মিনিটের ক্র্যাশ কোর্স)
আপনি যদি একজন রিয়্যাক্ট ডেভেলপার হন, তাহলে কম্পোনেন্ট তৈরি করা আপনার কাছে হয়তো ডাল-ভাত। কিন্তু এমন কোড লেখা যা পরিষ্কার (clean), সহজে রক্ষণাবেক্ষণযোগ্য (maintainable) এবং স্কেলেবল, সেটা কিন্তু মোটেও সহজ কাজ নয়।
কখনো কি এমন হয়েছে যে আপনি একটি কোডবেজে কাজ করতে গিয়ে মাকড়সার জালের মতো জট পাকানো কোডে আটকে গেছেন? অথবা ‘prop drilling’ এর যন্ত্রণায় অস্থির হয়ে ভেবেছেন, "ধুর! এটা করার কি আর কোনো ভালো উপায় নেই?"
যদি আপনার উত্তর "হ্যাঁ" হয়, তাহলে এই লেখাটি আপনার জন্যই। আজ আমরা রিয়্যাক্টের গভীরে ডুব দেব এবং বুঝব কেন ভালো কোড লেখার জন্য ডিজাইন প্যাটার্ন (Design Patterns) অপরিহার্য। সেই সাথে, রিয়্যাক্টের মূল ধারণাগুলোও ঝালিয়ে নেব কিছু চমৎকার বাস্তব জীবনের উপমা দিয়ে।
রিয়্যাক্ট কী? - শুধু একটি লাইব্রেরি নয়, একটি দর্শন!
ভিডিওটির শুরুতেই রিয়্যাক্টের একটি সুন্দর সংজ্ঞা দেওয়া হয়েছে:
React is a Declarative, Component-Based, JavaScript library for building user interfaces.
এই সংজ্ঞার মধ্যে চারটি গুরুত্বপূর্ণ শব্দ আছে। চলুন, সেগুলোকে বাস্তব জীবনের উদাহরণের মাধ্যমে বুঝে নিই।
১. Declarative (ঘোষণামূলক): কফির কাপের গল্প
প্রোগ্রামিংয়ের দুটি প্রধান ধরণ আছে: Declarative (ঘোষণামূলক) এবং Imperative (নির্দেশমূলক)।
-
Imperative পদ্ধতি (কীভাবে করতে হবে): ধরুন, আপনি আপনার সঙ্গীকে কফি বানাতে বললেন এবং ধাপে ধাপে নির্দেশ দিচ্ছেন: "প্রথমে একটি পাত্র নাও, তাতে এক কাপ জল দিয়ে গরম করো, তারপর এক চামচ কফি পাউডার দাও, চিনি মেশাও, ফুটিয়ে কাপে ঢালো।" এখানে আপনি কাজটি কীভাবে করতে হবে তার প্রতিটি ধাপ বলে দিচ্ছেন। ভ্যানিলা জাভাস্ক্রিপ্টে DOM ম্যানিপুলেশন অনেকটা এমনই। আমরা বলি:
document.getElementById('myElement').innerText = 'Hello'
। -
Declarative পদ্ধতি (কী করতে হবে): এবার ভাবুন, আপনি শুধু বললেন, "এক কাপ কালো কফি বানিয়ে দাও, প্লিজ।" আপনি শুধু বললেন কী চান, কিন্তু কীভাবে বানাতে হবে তা বললেন না। আপনার সঙ্গী কফি বানানোর প্রক্রিয়াটি নিজে থেকেই সম্পন্ন করলেন।
রিয়্যাক্ট ঠিক এভাবেই কাজ করে! আমরা রিয়্যাক্টকে বলে দিই যে কোনো একটি নির্দিষ্ট state বা ডেটার জন্য আমাদের ইউজার ইন্টারফেস (UI) দেখতে কেমন হবে। রিয়্যাক্ট নিজে থেকেই সেই state অনুযায়ী DOM আপডেট করার মতো কঠিন কাজগুলো করে ফেলে। আমাদের প্রতিটি ধাপ নিয়ে মাথা ঘামাতে হয় না। একারণেই রিয়্যাক্ট কোড অনেক বেশি predictable এবং সহজে বোঝা যায়।
২. Component-Based (কম্পোনেন্ট-ভিত্তিক): লেগো ব্লকের মতো
একটি বড় ওয়েবসাইটকে একটিমাত্র ফাইলে কোড করা কতটা কঠিন, তা নিশ্চয়ই আপনি জানেন। রিয়্যাক্ট এই সমস্যা সমাধান করে কম্পোনেন্ট-ভিত্তিক আর্কিটেকচারের মাধ্যমে।
ভাবুন তো, আপনি লেগো ব্লক (Lego blocks) দিয়ে একটি বড় বাড়ি বানাচ্ছেন। আপনি পুরো বাড়িটা একবারে না বানিয়ে ছোট ছোট ব্লক, যেমন—দেয়াল, জানালা, দরজা, ছাদ ইত্যাদি আলাদাভাবে তৈরি করে তারপর একসাথে জুড়ে দিচ্ছেন।
রিয়্যাক্টেও আমরা ঠিক তাই করি। একটি সম্পূর্ণ ওয়েবসাইটকে আমরা ছোট ছোট, স্বাধীন এবং পুনঃব্যবহারযোগ্য (reusable) অংশে ভাগ করে নিই, যেগুলোকে কম্পোনেন্ট বলে।
ভিডিওতে যেমন একটি স্কুলের রেজাল্ট পেজের উদাহরণ দেওয়া হয়েছে:
- App (পুরো অ্যাপ্লিকেশন)
- Navbar (নেভিগেশন বার)
- Results (রেজাল্টের সেকশন)
- Search (সার্চ বার)
- Scores (স্কোর দেখানোর টেবিল)
- ScoreHeading (টেবিলের হেডিং)
- ScoreList (ছাত্রদের তালিকা)
এই পদ্ধতিতে কাজ করলে কোড ম্যানেজ করা, ডিবাগ করা এবং টিমের সাথে কাজ করা অনেক সহজ হয়ে যায়।
৩. JavaScript Library (জাভাস্ক্রিপ্ট লাইব্রেরি)
রিয়্যাক্ট একটি ফ্রেমওয়ার্ক নয়, এটি একটি লাইব্রেরি। পার্থক্যটা হলো, লাইব্রেরি আপনাকে কিছু নির্দিষ্ট কাজ করার জন্য টুলস দেয় (যেমন রিয়্যাক্ট UI বানানোর টুলস দেয়), কিন্তু অ্যাপ্লিকেশনের বাকি অংশ কীভাবে সাজাবেন, সেই স্বাধীনতা আপনার। অন্যদিকে, ফ্রেমওয়ার্ক আপনাকে একটি নির্দিষ্ট কাঠামো দেয়, যার মধ্যে আপনাকে কাজ করতে হয়।
রিয়্যাক্ট শুধু UI তৈরির কাজটা করে। কিন্তু একটি পূর্ণাঙ্গ অ্যাপ্লিকেশনের জন্য আরও অনেক কিছু লাগে, যেমন:
- Routing (পেজ নেভিগেশন)
- Data Fetching (সার্ভার থেকে ডেটা আনা)
- State Management (জটিল ডেটা ম্যানেজমেন্ট)
- Testing
এগুলোর জন্য আমাদের রিয়্যাক্টের বিশাল ইকোসিস্টেম থেকে অন্যান্য লাইব্রেরি (যেমন React Router, TanStack Query, Redux) ব্যবহার করতে হয়।
আসল প্রশ্ন: ডিজাইন প্যাটার্ন জিনিসটা কী এবং কেন এটি দরকার?
সহজ কথায়, ডিজাইন প্যাটার্ন হলো কোনো একটি সাধারণ সমস্যার জন্য বারবার ব্যবহারযোগ্য একটি প্রমাণিত সমাধান।
এটা কোনো নির্দিষ্ট কোড বা লাইব্রেরি নয়, বরং এটি একটি ধারণা বা অ্যাপ্রোচ। ভাবুন, একজন সেরা শেফের একটি বিখ্যাত ডিশের রেসিপি। সেই রেসিপি অনুসরণ করলে যে কেউই মোটামুটি ভালো মানের একটি ডিশ তৈরি করতে পারবে। ডিজাইন প্যাটার্নও তেমনি কোড লেখার জন্য একটি পরীক্ষিত "রেসিপি"।
ভিডিওতে "Code Smell" নামে একটি দারুণ কনসেপ্টের কথা বলা হয়েছে। এর মানে হলো, আপনার কোড হয়তো এখন কাজ করছে, কিন্তু তার মধ্যে এমন কিছু লক্ষণ আছে যা দেখে বোঝা যায় ভবিষ্যতে এটি বড় ধরনের সমস্যা তৈরি করবে।
ডিজাইন প্যাটার্ন আমাদের এই "Code Smell" দূর করতে সাহায্য করে এবং নিশ্চিত করে যে আমাদের অ্যাপ্লিকেশনটি:
- পরিষ্কার ও পাঠযোগ্য (Clean & Readable): নতুন কোনো ডেভেলপার সহজেই কোড বুঝতে পারে।
- রক্ষণাবেক্ষণযোগ্য (Maintainable): ভবিষ্যতে কোনো পরিবর্তন বা বাগ ফিক্স করা সহজ হয়।
- পুনঃব্যবহারযোগ্য (Reusable): একই লজিক বা কম্পোনেন্ট বিভিন্ন জায়গায় ব্যবহার করা যায়।
- স্কেলেবল (Scalable): অ্যাপ্লিকেশন বড় হলেও এর পারফর্ম্যান্স এবং কোয়ালিটি ঠিক থাকে।
শেষ কথা
রিয়্যাক্ট শেখা এবং কম্পোনেন্ট তৈরি করা যাত্রার প্রথম ধাপ। কিন্তু একজন সাধারণ ডেভেলপার থেকে একজন অসাধারণ ডেভেলপার হয়ে ওঠার জন্য আপনাকে শিখতে হবে কীভাবে পরিষ্কার, দক্ষ এবং শক্তিশালী কোড লিখতে হয়। আর এখানেই ডিজাইন প্যাটার্নের ভূমিকা।
ভিডিওতে যে ১৫ দিনের সিরিজের কথা বলা হয়েছে, সেখানে Container-Presenter, Higher-Order Components (HOC), Custom Hooks, Render Props এর মতো অনেক গুরুত্বপূর্ণ প্যাটার্ন শেখানো হবে। এই প্যাটার্নগুলো আয়ত্ত করতে পারলে আপনি শুধু কোড লিখবেন না, আপনি কোড দিয়ে শিল্প তৈরি করবেন।
গুরুত্বপূর্ণ কিছু রিঅ্যাক্ট ডিজাইন প্যাটার্ন ও কোড উদাহরণ 📝
ভিডিওটিতে ১৫টি গুরুত্বপূর্ণ ডিজাইন প্যাটার্নের কথা বলা হয়েছে। এর মধ্যে কিছু নিচে উদাহরণসহ তুলে ধরা হলো:
-
Container Presenter Pattern: কন্টেইনার কম্পোনেন্ট ডেটা এবং লজিক হ্যান্ডেল করে এবং প্রেজেন্টেশনাল কম্পোনেন্ট শুধু UI রেন্ডার করে [13:47 (opens in a new tab)]।
-
উদাহরণ:
// Container Component function UserListContainer() { const [users, setUsers] = useState([]); useEffect(() => { fetch("https://api.example.com/users") .then((response) => response.json()) .then((data) => setUsers(data)); }, []); return <UserList users={users} />; } // Presentational Component function UserList({ users }) { return ( <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> ); }
-
-
Controlled vs. Uncontrolled Component Pattern: ফর্ম ইনপুট ফিল্ডের ভ্যালু রিঅ্যাক্ট স্টেট দ্বারা নিয়ন্ত্রিত হলে তাকে কন্ট্রোল্ড কম্পোনেন্ট বলে, আর DOM নিজেই ভ্যালু নিয়ন্ত্রণ করলে তাকে আনকন্ট্রোল্ড কম্পোনেন্ট বলে [14:10 (opens in a new tab)]।
-
উদাহরণ:
// Controlled Component function ControlledForm() { const [value, setValue] = useState(""); const handleChange = (event) => { setValue(event.target.value); }; return <input type="text" value={value} onChange={handleChange} />; }
-
-
Custom Hooks Pattern: রিইউজেবল লজিককে কম্পোনেন্ট থেকে আলাদা করে কাস্টম হুক-এর মধ্যে রাখা হয় [15:59 (opens in a new tab)]।
-
উদাহরণ:
// Custom Hook function useFetch(url) { const [data, setData] = useState(null); useEffect(() => { fetch(url) .then((response) => response.json()) .then((data) => setData(data)); }, [url]); return data; } // Usage in a component function UserProfile() { const user = useFetch("https://api.example.com/user/1"); // ... render user profile }
-
http://www.youtube.com/watch?v=OWi31QoHqNk&t=1085 (opens in a new tab)