আপনার UI-কে একটি ট্রি (Tree) হিসাবে বোঝা 🌳
আপনার React অ্যাপটি ধীরে ধীরে একটি আকার নিচ্ছে, যেখানে অনেকগুলো কম্পোনেন্ট একটির ভেতর আরেকটি বসানো (nested) আছে। কিন্তু React কীভাবে আপনার অ্যাপের এই কম্পোনেন্টের গঠন মনে রাখে?
React এবং অন্যান্য অনেক UI লাইব্রেরি, ইউজার ইন্টারফেসকে (UI) একটি ট্রি (tree) বা গাছের মতো করে মডেল করে। আপনার অ্যাপকে একটি ট্রি হিসেবে কল্পনা করলে কম্পোনেন্টগুলোর মধ্যে সম্পর্ক বোঝা অনেক সহজ হয়ে যায়। এই ধারণাটি আপনাকে ভবিষ্যতে পারফরম্যান্স (performance) এবং স্টেট ম্যানেজমেন্টের (state management) মতো জটিল বিষয়গুলো ডিবাগ করতে সাহায্য করবে।
আপনি যা শিখবেন
- React কীভাবে কম্পোনেন্টের গঠনকে "দেখে"।
- রেন্ডার ট্রি (Render Tree) কী এবং এটি কী কাজে লাগে।
- মডিউল ডিপেন্ডেন্সি ট্রি (Module Dependency Tree) কী এবং এটি কী কাজে লাগে।
আপনার UI একটি ট্রি হিসাবে
ট্রি হলো বিভিন্ন আইটেমের মধ্যে সম্পর্ক দেখানোর একটি মডেল। ইউজার ইন্টারফেসকে প্রায়ই ট্রি স্ট্রাকচার ব্যবহার করে দেখানো হয়। উদাহরণস্বরূপ, ব্রাউজারগুলো HTML মডেল করার জন্য DOM (Document Object Model) এবং CSS মডেল করার জন্য CSSOM (CSS Object Model) ব্যবহার করে, যা দুটিই ট্রি স্ট্রাকচার। মোবাইল প্ল্যাটফর্মগুলোও তাদের ভিউ হায়ারার্কি (view hierarchy) দেখানোর জন্য ট্রি ব্যবহার করে।
এই ডায়াগ্রামটি React কীভাবে আপনার লেখা কোডকে ব্রাউজারে প্রদর্শন করে, তার পুরো প্রক্রিয়াটি ধাপে ধাপে দেখায়:
১. কম্পোনেন্ট কোড (বাম দিক): প্রথমে, আপনি আপনার প্রোজেক্টে আলাদা আলাদা কম্পোনেন্ট (Component A, Component B, Component C) তৈরি করেন।
২. React-এর কম্পোনেন্ট ট্রি (মাঝের অংশ): এরপর, React আপনার লেখা কম্পোনেন্টগুলো নিয়ে তাদের মধ্যেকার সম্পর্ক অনুযায়ী একটি ভার্চুয়াল ট্রি তৈরি করে। এখানে A হলো প্যারেন্ট এবং B ও C তার চাইল্ড। এটি React-এর নিজস্ব একটি গঠন, যা আসল DOM নয়।
৩. আসল DOM ট্রি (ডান দিক): সবশেষে, React DOM লাইব্রেরিটি React-এর তৈরি করা ভার্চুয়াল ট্রি-কে ব্রাউজারের বোধগম্য আসল HTML এলিমেন্টে (DOM নোড) পরিণত করে। ডায়াগ্রামের শেষ অংশে দেখানো ব্রাউজারের সম্পূর্ণ DOM ট্রি-এর মধ্যে হাইলাইট করা অংশটিই হলো আমাদের React কম্পোনেন্ট থেকে তৈরি হওয়া অংশ।
সহজ কথায়, আপনি কম্পোনেন্ট লেখেন, React সেগুলোর একটি যৌক্তিক ট্রি তৈরি করে এবং React DOM সেই ট্রি-কে ব্রাউজারে দেখানোর জন্য আসল HTML-এ রূপান্তরিত করে।
React আপনার কম্পোনেন্টগুলো থেকে একটি UI ট্রি তৈরি করে। এই উদাহরণে, UI ট্রিটি এরপর DOM-এ রেন্ডার করার জন্য ব্যবহৃত হয়।
ব্রাউজার এবং মোবাইল প্ল্যাটফর্মের মতোই, React-ও একটি অ্যাপের কম্পোনেন্টগুলোর মধ্যে সম্পর্ক ম্যানেজ এবং মডেল করার জন্য ট্রি স্ট্রাকচার ব্যবহার করে। এই ট্রিগুলো একটি React অ্যাপের মাধ্যমে ডেটা কীভাবে প্রবাহিত হয় এবং রেন্ডারিং ও অ্যাপের সাইজ কীভাবে অপ্টিমাইজ করা যায়, তা বোঝার জন্য খুবই দরকারী টুল।
রেন্ডার ট্রি (The Render Tree)
কম্পোনেন্টের একটি প্রধান বৈশিষ্ট্য হলো অন্য কম্পোনেন্ট ব্যবহার করে নতুন কম্পোনেন্ট তৈরি করা। যখন আমরা কম্পোনেন্টগুলোকে একটির ভেতর আরেকটি রাখি (nesting), তখন প্যারেন্ট (parent) এবং চাইল্ড (child) কম্পোনেন্টের ধারণাটি আসে, যেখানে প্রতিটি প্যারেন্ট কম্পোনেন্ট নিজেই অন্য কোনো কম্পোনেন্টের চাইল্ড হতে পারে।
যখন আমরা একটি React অ্যাপ রেন্ডার করি, তখন আমরা এই সম্পর্কটিকে একটি ট্রি-তে মডেল করতে পারি, যা রেন্ডার ট্রি নামে পরিচিত।
এখানে একটি React অ্যাপের উদাহরণ দেওয়া হলো যা অনুপ্রেরণামূলক উক্তি (inspirational quotes) রেন্ডার করে।
import FancyText from "./FancyText";
import InspirationGenerator from "./InspirationGenerator";
import Copyright from "./Copyright";
export default function App() {
return (
<>
<FancyText title text="Get Inspired App" />
<InspirationGenerator>
<Copyright year={2004} />
</InspirationGenerator>
</>
);
}export default function FancyText({ title, text }) {
return title ? (
<h1 className="fancy title">{text}</h1>
) : (
<h3 className="fancy cursive">{text}</h3>
);
}import * as React from "react";
import quotes from "./quotes";
import FancyText from "./FancyText";
export default function InspirationGenerator({ children }) {
const [index, setIndex] = React.useState(0);
const quote = quotes[index];
const next = () => setIndex((index + 1) % quotes.length);
return (
<>
<p>Your inspirational quote is:</p>
<FancyText text={quote} />
<button onClick={next}>Inspire me again</button>
{children}
</>
);
}export default function Copyright({ year }) {
return <p className="small">©️ {year}</p>;
}export default [
"Don’t let yesterday take up too much of today.” — Will Rogers",
"Ambition is putting a ladder against the sky.",
"A joy that's shared is a joy made double.",
];.fancy {
font-family: "Georgia";
}
.title {
color: #007aa3;
text-decoration: underline;
}
.cursive {
font-style: italic;
}
.small {
font-size: 10px;
}
এই ডায়াগ্রামটি একটি রেন্ডার ট্রি (Render Tree) দেখাচ্ছে, যা একটি নির্দিষ্ট মুহূর্তে আপনার UI-তে কম্পোনেন্টগুলোর রেন্ডারিং সম্পর্ক তুলে ধরে।
এখানে প্রতিটি নোড (node) একটি করে React কম্পোনেন্ট।
Appহলো এই ট্রি-এর রুট (root) বা মূল কম্পোনেন্ট।Appকম্পোনেন্টটি তার ভেতরে দুটি চাইল্ড কম্পোনেন্ট রেন্ডার করছে:InspirationGeneratorএবংFancyText। তীরগুলোতে "renders" লেখা দিয়ে এটাই বোঝানো হয়েছে।- একইভাবে,
InspirationGeneratorকম্পোনেন্টটি তার নিজের ভেতরে আরও দুটি কম্পোনেন্ট রেন্ডার করছে: আরেকটিFancyTextএবংCopyright।
সহজ কথায়, এই ট্রি দেখায় যে কোন প্যারেন্ট কম্পোনেন্ট কোন চাইল্ড কম্পোনেন্টগুলোকে স্ক্রিনে প্রদর্শন করছে।
React একটি রেন্ডার ট্রি তৈরি করে, যা রেন্ডার হওয়া কম্পোনেন্টগুলো নিয়ে গঠিত একটি UI ট্রি।
উপরের অ্যাপটি থেকে, আমরা এই রেন্ডার ট্রি-টি তৈরি করতে পারি।
এই ট্রি-টি নোড (node) দিয়ে গঠিত, যার প্রতিটি একটি কম্পোনেন্টকে প্রতিনিধিত্ব করে। App, FancyText, Copyright - এগুলো সবই আমাদের ট্রি-এর এক একটি নোড।
একটি React রেন্ডার ট্রি-এর একদম উপরের বা রুট নোড (root node) হলো অ্যাপের রুট কম্পোনেন্ট (root component)। এই ক্ষেত্রে, রুট কম্পোনেন্ট হলো App এবং এটিই প্রথম কম্পোনেন্ট যা React রেন্ডার করে। ট্রি-এর প্রতিটি তীর একটি প্যারেন্ট কম্পোনেন্ট থেকে একটি চাইল্ড কম্পোনেন্টের দিকে নির্দেশ করে।
আরও গভীরে: রেন্ডার ট্রি-তে HTML ট্যাগগুলো কোথায়? 🤔
আপনি উপরের রেন্ডার ট্রি-তে লক্ষ্য করবেন যে, প্রতিটি কম্পোনেন্ট যে
<h1>বা<p>এর মতো HTML ট্যাগগুলো রেন্ডার করে, তার কোনো উল্লেখ নেই। এর কারণ হলো রেন্ডার ট্রি শুধুমাত্র React কম্পোনেন্ট দিয়ে গঠিত।
React একটি UI ফ্রেমওয়ার্ক হিসেবে প্ল্যাটফর্ম-অ্যাগনস্টিক (platform agnostic), অর্থাৎ এটি কোনো নির্দিষ্ট প্ল্যাটফর্মের উপর নির্ভরশীল নয়। আমরা এখানে ওয়েবের জন্য উদাহরণ দেখাচ্ছি, যা UI দেখানোর জন্য HTML ট্যাগ ব্যবহার করে। কিন্তু একটি React অ্যাপ মোবাইল বা ডেস্কটপ প্ল্যাটফর্মেও চলতে পারে, যেখানে UIView (iOS) বা FrameworkElement (Windows) এর মতো ভিন্ন UI প্রিমিটিভ ব্যবহার করা হতে পারে।
এই প্ল্যাটফর্ম-নির্দিষ্ট UI প্রিমিটিভগুলো React-এর অংশ নয়। তাই React রেন্ডার ট্রি আমাদের অ্যাপ সম্পর্কে ধারণা দেয়, অ্যাপটি কোন প্ল্যাটফর্মে চলছে তা নির্বিশেষে।
একটি রেন্ডার ট্রি একটি React অ্যাপ্লিকেশনের একটিমাত্র রেন্ডার পাস (single render pass) দেখায়। কন্ডিশনাল রেন্ডারিং ব্যবহার করে একটি প্যারেন্ট কম্পোনেন্ট বিভিন্ন ডেটার উপর ভিত্তি করে ভিন্ন ভিন্ন চাইল্ড রেন্ডার করতে পারে।
এখন আমরা অ্যাপটিকে এমনভাবে আপডেট করব যাতে এটি শর্ত অনুযায়ী একটি উক্তি অথবা একটি রঙ রেন্ডার করতে পারে।
import FancyText from "./FancyText";
import InspirationGenerator from "./InspirationGenerator";
import Copyright from "./Copyright";
export default function App() {
return (
<>
<FancyText title text="Get Inspired App" />
<InspirationGenerator>
<Copyright year={2004} />
</InspirationGenerator>
</>
);
}export default function FancyText({ title, text }) {
return title ? (
<h1 className="fancy title">{text}</h1>
) : (
<h3 className="fancy cursive">{text}</h3>
);
}export default function Color({ value }) {
return <div className="colorbox" style={{ backgroundColor: value }} />;
}import * as React from "react";
import inspirations from "./inspirations";
import FancyText from "./FancyText";
import Color from "./Color";
export default function InspirationGenerator({ children }) {
const [index, setIndex] = React.useState(0);
const inspiration = inspirations[index];
const next = () => setIndex((index + 1) % inspirations.length);
return (
<>
<p>Your inspirational {inspiration.type} is:</p>
{inspiration.type === "quote" ? (
<FancyText text={inspiration.value} />
) : (
<Color value={inspiration.value} />
)}
<button onClick={next}>Inspire me again</button>
{children}
</>
);
}export default function Copyright({ year }) {
return <p className="small">©️ {year}</p>;
}export default [
{
type: "quote",
value: "Don’t let yesterday take up too much of today.” — Will Rogers",
},
{ type: "color", value: "#B73636" },
{ type: "quote", value: "Ambition is putting a ladder against the sky." },
{ type: "color", value: "#256266" },
{ type: "quote", value: "A joy that's shared is a joy made double." },
{ type: "color", value: "#F9F2B4" },
];.fancy {
font-family: "Georgia";
}
.title {
color: #007aa3;
text-decoration: underline;
}
.cursive {
font-style: italic;
}
.small {
font-size: 10px;
}
.colorbox {
height: 100px;
width: 100px;
margin: 8px;
}
এই ডায়াগ্রামটি দেখাচ্ছে কীভাবে কন্ডিশনাল রেন্ডারিং (Conditional Rendering) এর কারণে একটি রেন্ডার ট্রি পরিবর্তিত হতে পারে।
এখানে, App কম্পোনেন্টটি সবসময় InspirationGenerator এবং FancyText রেন্ডার করে, যা সলিড বা গাঢ় লাইন দিয়ে দেখানো হয়েছে।
তবে, InspirationGenerator কম্পোনেন্টের ভেতরের চিত্রটি ভিন্ন:
- এটি শর্তসাপেক্ষে হয়
FancyTextঅথবাColorকম্পোনেন্ট রেন্ডার করে। ড্যাশ (---) লাইন এবং প্রশ্নবোধক চিহ্ন (?) দিয়ে এই শর্তটি বোঝানো হচ্ছে যে, দুটির মধ্যে যেকোনো একটি রেন্ডার হবে, দুটো একসাথে নয়। - একই সাথে, এটি সবসময়
Copyrightকম্পোনেন্টটিও রেন্ডার করে (যা সলিড লাইন দিয়ে দেখানো হয়েছে)।
কন্ডিশনাল রেন্ডারিংয়ের সাথে, বিভিন্ন রেন্ডারে, রেন্ডার ট্রি ভিন্ন ভিন্ন কম্পোনেন্ট রেন্ডার করতে পারে। এই ডায়াগ্রামটি ঠিক এই ধারণাই তুলে ধরেছে।
এই উদাহরণে, inspiration.type-এর মানের উপর নির্ভর করে, আমরা <FancyText> অথবা <Color> কম্পোনেন্ট রেন্ডার করছি। এর মানে, প্রতিটি রেন্ডার পাসের জন্য রেন্ডার ট্রি ভিন্ন হতে পারে।
রেন্ডার ট্রি পরিবর্তনশীল হলেও, এটি আমাদের অ্যাপের টপ-লেভেল (top-level) এবং লিফ (leaf) কম্পোনেন্টগুলো শনাক্ত করতে সাহায্য করে।
- টপ-লেভেল কম্পোনেন্ট: এগুলো রুট কম্পোনেন্টের সবচেয়ে কাছের কম্পোনেন্ট। এরা নিজেদের নিচের সমস্ত কম্পোনেন্টের রেন্ডারিং পারফরম্যান্সকে প্রভাবিত করে।
- লিফ কম্পোনেন্ট: এগুলো ট্রি-এর একদম নিচের দিকের কম্পোনেন্ট, যাদের কোনো চাইল্ড কম্পোনেন্ট থাকে না। এরা প্রায়শই পুনরায় রেন্ডার হয়।
এই দুই ধরণের কম্পোনেন্ট শনাক্ত করতে পারলে অ্যাপের ডেটা ফ্লো এবং পারফরম্যান্স বোঝা সহজ হয়।
মডিউল ডিপেন্ডেন্সি ট্রি (The Module Dependency Tree) ⚙️
React অ্যাপের আরেকটি সম্পর্ক যা ট্রি দিয়ে মডেল করা যায়, তা হলো অ্যাপের মডিউল ডিপেন্ডেন্সি। যখন আমরা আমাদের কম্পোনেন্ট এবং লজিককে আলাদা আলাদা ফাইলে (.js ফাইল) ভাগ করি, তখন আমরা JavaScript মডিউল তৈরি করি। এই ফাইলগুলো থেকে আমরা কম্পোনেন্ট, ফাংশন বা কনস্ট্যান্ট export করি এবং অন্য ফাইলে import করি।
একটি মডিউল ডিপেন্ডেন্সি ট্রি-এর প্রতিটি নোড হলো একটি মডিউল (একটি ফাইল) এবং প্রতিটি শাখা সেই ফাইলে থাকা একটি import স্টেটমেন্টকে প্রতিনিধিত্ব করে।
আমরা যদি আগের Inspirations অ্যাপটির জন্য একটি মডিউল ডিপেন্ডেন্সি ট্রি তৈরি করি, তবে তা দেখতে এমন হবে:
এই ডায়াগ্রামটি একটি মডিউল ডিপেন্ডেন্সি ট্রি (Module Dependency Tree) দেখাচ্ছে, যা আপনার প্রোজেক্টের ফাইলগুলোর মধ্যেকার import সম্পর্ককে তুলে ধরে।
এখানে প্রতিটি নোড (node) একটি ফাইল বা মডিউল (যেমন .js ফাইল) এবং প্রতিটি তীর (arrow) একটি import স্টেটমেন্টকে প্রতিনিধিত্ব করে।
App.jsহলো এই অ্যাপ্লিকেশনের মূল ফাইল। এটি তার কাজের জন্য তিনটি মডিউল ইম্পোর্ট করছে:InspirationGenerator.js,FancyText.js, এবংCopyright.js।- একইভাবে,
InspirationGenerator.jsফাইলটি নিজে আরও তিনটি মডিউল ইম্পোর্ট করছে:FancyText.js,Color.js, এবংinspirations.js।
সহজ কথায়, এই ট্রি দেখায় যে একটি ফাইলকে চলতে গেলে অন্য কোন কোন ফাইলের উপর নির্ভর করতে হয়। এটি কম্পোনেন্টের রেন্ডারিং সম্পর্ক দেখায় না, বরং ফাইলগুলোর একে অপরের উপর নির্ভরশীলতা (dependency) দেখায়।
এই ট্রি-এর রুট নোড হলো রুট মডিউল, যা এন্ট্রি পয়েন্ট ফাইল (entrypoint file) নামেও পরিচিত। সাধারণত এই ফাইলে রুট কম্পোনেন্টটি থাকে।
এই ট্রি-কে যদি আমরা রেন্ডার ট্রি-এর সাথে তুলনা করি, তাহলে কিছু মিল থাকলেও কিছু গুরুত্বপূর্ণ পার্থক্য দেখতে পাবো:
- নোডের ধরণ: এই ট্রি-এর নোডগুলো হলো মডিউল (ফাইল), কম্পোনেন্ট নয়।
- নন-কম্পোনেন্ট মডিউল:
inspirations.jsএর মতো ফাইল, যা কোনো কম্পোনেন্ট নয়, সেটিও এই ট্রি-তে থাকে। কিন্তু রেন্ডার ট্রি-তে শুধুমাত্র কম্পোনেন্ট থাকে। - গঠনগত পার্থক্য:
Copyright.jsমডিউলটিApp.js-এর অধীনে দেখাচ্ছে কারণApp.jsফাইলটি তাকে ইম্পোর্ট করে। কিন্তু রেন্ডার ট্রি-তেCopyrightকম্পোনেন্টটিInspirationGenerator-এর চাইল্ড হিসেবে দেখানো হয়। এর কারণInspirationGeneratorকম্পোনেন্টটিCopyright-কেchildrenprop হিসেবে রেন্ডার করে, কিন্তুCopyright.jsমডিউলটি সরাসরি ইম্পোর্ট করে না।
ডিপেন্ডেন্সি ট্রিগুলো বুঝতে সাহায্য করে যে আপনার অ্যাপটি চালাতে কোন কোন ফাইল বা মডিউলগুলো প্রয়োজন। যখন আপনি প্রোডাকশনের জন্য অ্যাপ বিল্ড করেন, তখন একটি বান্ডলার (bundler) (যেমন Webpack, Vite) এই ডিপেন্ডেন্সি ট্রি ব্যবহার করে সমস্ত প্রয়োজনীয় কোডকে একত্রিত করে একটি ফাইলে পরিণত করে, যা ক্লায়েন্টের ব্রাউজারে পাঠানো হয়।
আপনার অ্যাপ যত বড় হবে, বান্ডেলের সাইজও তত বাড়বে। বড় বান্ডেল সাইজ ব্যবহারকারীর জন্য অ্যাপ লোড হতে দেরি করায়। আপনার অ্যাপের ডিপেন্ডেন্সি ট্রি সম্পর্কে ধারণা থাকলে এই ধরনের সমস্যা খুঁজে বের করা এবং সমাধান করা সহজ হয়।
সারসংক্ষেপ 📝
- ট্রি হলো বিভিন্ন জিনিসের মধ্যে সম্পর্ক দেখানোর একটি সাধারণ উপায়, যা প্রায়ই UI মডেল করতে ব্যবহৃত হয়।
- রেন্ডার ট্রি একটি রেন্ডারের সময় React কম্পোনেন্টগুলোর নেস্টেড সম্পর্ককে দেখায়।
- কন্ডিশনাল রেন্ডারিংয়ের কারণে বিভিন্ন রেন্ডারে রেন্ডার ট্রি পরিবর্তিত হতে পারে।
- রেন্ডার ট্রি আমাদের টপ-লেভেল এবং লিফ কম্পোনেন্ট শনাক্ত করতে সাহায্য করে, যা রেন্ডারিং পারফরম্যান্স বুঝতে ও ডিবাগ করতে দরকারী।
- ডিপেন্ডেন্সি ট্রি একটি React অ্যাপের মডিউল বা ফাইলগুলোর
importসম্পর্ককে দেখায়। - বান্ডলারগুলো এই ডিপেন্ডেন্সি ট্রি ব্যবহার করে প্রোডাকশনের জন্য প্রয়োজনীয় কোড একত্রিত করে।
- ডিপেন্ডেন্সি ট্রি অ্যাপের বান্ডেল সাইজ বড় হয়ে যাওয়ার মতো সমস্যা ডিবাগ করতে এবং কোড অপটিমাইজ করার সুযোগ খুঁজে বের করতে সহায়ক।