کامپوننت ها (Components)
در ری اکت، کامپوننت های ری اکت مثل تکه های لگو هستند. هر تکه یک کار مشخص انجام می دهد و یک تکه رابط کاربری برمی گرداند. با چیدن این کامپوننت ها کنار هم، مثل ساختن یک شهر کوچک با لگو، یک اپلیکیشن کامل می سازی.
کامپوننت های ری اکت دقیقا چه هستند؟
کامپوننت (Component) یک تکه کد مستقل و قابل استفاده مجدد است. این کد در ری اکت مثل یک تابع جاوااسکریپت کار می کند، اما در نهایت به جای عدد یا متن ساده، کد HTML برمی گرداند.
کامپوننت ها در ری اکت دو مدل کلی دارند: کامپوننت های کلاسی و کامپوننت های تابعی. در پروژه های جدید معمولا از کامپوننت های تابعی همراه با هوک ها استفاده می کنیم.
نکته: در کدهای قدیمی تر ممکن است بیشتر کامپوننت های کلاسی ببینی. اما الان تمرکز اصلی روی کامپوننت های تابعی است و این درس هم روی همین نوع تمرکز دارد.
ساخت اولین کامپوننت تابعی
نام هر کامپوننت در ری اکت باید با حرف بزرگ شروع شود. این قانون مهم است، چون ری اکت بر اساس حرف اول تشخیص می دهد که این یک تگ HTML است یا یک کامپوننت ساخته شده توسط خودت.
مثال: کامپوننت ساده Car
function Car() {
return (
<h2>Hi, I am a Car!</h2>
);
}
در این مثال، تابع Car یک کامپوننت است. این تابع هیچ ورودی نمی گیرد و فقط یک تگ h2 برمی گرداند. هر وقت در JSX از <Car /> استفاده کنی، همین متن نمایش داده می شود.
نمایش یک کامپوننت روی صفحه
حالا که کامپوننت Car را ساختی، باید آن را روی صفحه نمایش بدهی. برای این کار از createRoot(...).render(...) استفاده می شود تا محتوای ری اکت داخل یک المنت ریشه مثل root قرار بگیرد.
مثال: رندر کردن کامپوننت Car
createRoot(document.getElementById("root")).render(
<Car />
);
اول المنت با id برابر root پیدا می شود. بعد متد render کامپوننت <Car /> را داخل آن نمایش می دهد. مثل این است که بگویی: «ری اکت! اینجا صفحه اصلی است، این هم تکه ای که باید نشان بدهی.»
پراپس ها (Props)؛ ورودی های کامپوننت
گاهی می خواهی کامپوننت فقط یک متن ثابت نباشد. می خواهی شبیه تابع های معمولی، ورودی بگیرد. در ری اکت این ورودی ها را پراپس (Props) می نامیم که مخفف Properties است.
پراپس ها به شکل ویژگی های HTML به کامپوننت فرستاده می شوند. بعد داخل تابع کامپوننت، از شیء props برای خواندن این مقدارها استفاده می کنی.
مثال: ارسال رنگ به کامپوننت Car
function Car(props) {
return (
<h2>I am a {props.color} Car!</h2>
);
}
createRoot(document.getElementById("root")).render(
<Car color="red" />
);
کامپوننت Car یک پارامتر به نام props می گیرد. هنگام رندر، پراپس color را با مقدار "red" می فرستیم. داخل JSX، از {props.color} استفاده می کنیم تا این رنگ در متن نمایش داده شود.
نکته: پراپس ها فقط خواندنی هستند. یعنی کامپوننت حق ندارد مقدار پراپس را مستقیم عوض کند.
کامپوننت ها داخل هم؛ گاراژ و ماشین ها
یکی از قدرت های کامپوننت های ری اکت این است که می توانی آن ها را داخل هم استفاده کنی. یعنی یک کامپوننت والد، چند کامپوننت فرزند را در خود نگه دارد؛ مثل یک گاراژ که داخلش چند ماشین است.
مثال: استفاده از Car داخل کامپوننت Garage
function Car() {
return (
<h2>I am a Car!</h2>
);
}
function Garage() {
return (
<>
<h1>Who lives in my Garage?</h1>
<Car />
</>
);
}
createRoot(document.getElementById("root")).render(
<Garage />
);
کامپوننت Garage یک تیتر نشان می دهد و بعد کامپوننت Car را صدا می زند. تگ خالی <>...</> را فرگمنت (Fragment) می نامیم؛ فقط چند عنصر را بدون اضافه کردن div اضافه می کند.
رندر چندباره یک کامپوننت
وقتی یک کامپوننت ساختی، می توانی آن را چندبار استفاده کنی. هر استفاده مثل یک نمونه جدید از همان تکه لگو است.
مثال: استفاده دو بار از Car
function Car() {
return (
<h2>I am a Car!</h2>
);
}
function Garage() {
return (
<>
<h1>Who lives in my Garage?</h1>
<Car />
<Car />
</>
);
}
createRoot(document.getElementById("root")).render(
<Garage />
);
اینجا دو بار از <Car /> استفاده کرده ایم. بنابراین همان متن دو بار نمایش داده می شود. حالا اگر کامپوننت از پراپس استفاده کند، می توانی هر بار اطلاعات متفاوتی به آن بدهی.
مثال: دو ماشین مختلف با پراپس brand
function Car(props) {
return (
<h2>I am a {props.brand}!</h2>
);
}
function Garage() {
return (
<>
<h1>Who lives in my Garage?</h1>
<Car brand="Ford" />
<Car brand="BMW" />
</>
);
}
createRoot(document.getElementById("root")).render(
<Garage />
);
در این مثال، هردو بار از یک کامپوننت استفاده شده است. اما چون پراپس brand در هر بار متفاوت است، خروجی هم دو ماشین با برندهای مختلف می شود.
گذاشتن کامپوننت ها در فایل جدا
برای مرتب شدن پروژه، بهتر است بعضی کامپوننت های ری اکت را در فایل جدا قرار بدهی. مثلا هر کامپوننت مهم یک فایل اختصاصی داشته باشد. این کار پیدا کردن و استفاده کردن از کامپوننت ها را بسیار ساده می کند.
مثال: فایل Vehicle.jsx برای کامپوننت Car
function Car() {
return (
<h2>Hi, I am a Car!</h2>
);
}
export default Car;
کد بالا داخل فایلی به نام Vehicle.jsx قرار می گیرد. در پایان، با export default Car این کامپوننت را برای استفاده در فایل های دیگر در دسترس قرار می دهی.
مثال: ایمپورت کردن کامپوننت از فایل جدا
import { createRoot } from "react-dom/client";
import Car from "./Vehicle.jsx";
createRoot(document.getElementById("root")).render(
<Car />
);
در این فایل، اول createRoot را از کتابخانه react-dom/client وارد می کنیم. بعد کامپوننت Car را از فایل Vehicle.jsx ایمپورت می کنیم و آن را داخل المنت root نمایش می دهیم.
گام های تمرینی برای کامپوننت ها
برای اینکه مفاهیم کامپوننت های ری اکت خوب در ذهنت بماند، این سه تمرین را انجام بده.
- یک کامپوننت ساده به نام
Studentبساز که یک پیام سلام نمایش دهد. سپس آن را با<Student />در روت رندر کن. - کامپوننت
Studentرا طوری تغییر بده که یک پراپس مثلnameبگیرد و نام دانش آموز را در متن نمایش دهد. - یک کامپوننت
Classroomبساز که داخل آن چند بار ازStudentبا نام های مختلف استفاده کند؛ مثل یک لیست کلاس.
بعد از این تمرین ها، می توانی سراغ بخش مقدمه JSX (JSX Intro) بروی تا بهتر بفهمی این تگ های شبیه HTML در کامپوننت ها دقیقا چگونه کار می کنند.
همچنین در فصل شرط ها در JSX (JSX If Statements) می بینی چگونه می توانی رفتار کامپوننت ها را با شرط ها و تصمیم گیری ها هوشمندتر کنی.
جمع بندی سریع
- کامپوننت های ری اکت مثل تکه های لگو، قابل استفاده مجدد هستند.
- نام کامپوننت همیشه باید با حرف بزرگ شروع شود.
- کامپوننت ها تابع هایی هستند که در نهایت JSX برمی گردانند.
- با پراپس می توانی به کامپوننت ها ورودی های مختلف بدهی.
- می توانی کامپوننت ها را در فایل های جدا نگه داری و در جاهای مختلف ایمپورت کنی.