Codoloper

تفاوت React Element، JSX Element و React Node چیست؟

تفاوت React Element، JSX Element و React Node چیست؟ | عکس

اگر در حال توسعه پروژه‌های ری‌اکت یا نکست‌جی‌اس با TypeScript هستید، قطعا موقع نوشتن کامپوننت‌ها یا تعریف تمپلیت‌ها، به این سه تایپ (Type) برخوردید: ReactNode ،ReactElement و JSX.Element.

در این مقاله می‌خوایم به زبون ساده و با مثال‌های واقعی بررسی کنیم که این سه مفهوم دقیقاً چی هستن، چه تفاوتی با هم دارن و در چه سناریویی باید از کدومشون استفاده کنیم.
۱. مفهوم React Element:
یک React Element کوچک‌ترین واحد سازنده در یک اپلیکیشن ری‌اکت هستش. از نظر فنی، این تایپ یک شیء (Object) ساده و جاوااسکریپتیه که توصیف می‌کنه یک جزء از پورتال یا UI شما چطور باید به نظر برسه (مثلاً نوعش چیه، چه Propsهایی داره و فرزندانش کدوم هستن).
وقتی شما یک کامپوننت یا تگ HTML رو می‌نویسین، ری‌اکت در پشت صحنه اون رو به یک الگو تبدیل می‌کنه.
چه زمانی تولید می‌شه؟ هر زمانی که تابع React.createElement() فراخوانی شه.
ویژگی مهم: این تایپ نمی‌تونه شامل متن ساده (String)، عدد یا آرایه باشه؛ بلکه فقط و فقط یک آبجکت معتبر ری‌آکتیه.

// این یک ReactElement است
const element: React.ReactElement = <h1>سلام کادولوپر!</h1>; 

// این خطا ایجاد می‌کند چون رشته متنی به تنهایی ReactElement نیست
const invalidElement: React.ReactElement = "Hello World"; // Error!
۲. مفهوم JSX.Element:
JSX.Element و React Element: این دو تقریباً یک چیز هستن! در واقع JSX.Element یک متغیر سراسری (Global) هستش که توسط خود زبان جاوااسکریپت/تایپ‌اسکریپت (درست خارج از هسته ری‌اکت) تعریف میشه تا خروجی سینتکس‌های JSX رو تایپ‌دهی کنه. از نظر ساختاری، JSX.Element چیزی نیست بجز یک اینترفیس که مستقیماً از ReactElement ارث‌بری می‌کنه، اما با این تفاوت که تایپِ فیلدهای props و type اون به صورت پیش‌فرض any در نظر گرفته شده تا منعطف‌تر باشه.
// هر دو خط زیر از نظر عملکردی کاملاً یکسان هستند:
const buttonOne: React.ReactElement = <button>کلیک کنید</button>;
const buttonTwo: JSX.Element = <button>کلیک کنید</button>;
۳. مفهوم React Node:
می‌رسیم به بزرگ‌ترین تایپ در ری‌آکت: React Node.
تایپ ReactNode در واقع یک ابرمجموعه (Superset) هستش؛ یعنی هر چیزی که ری‌آکت توانایی رندر کردن اون رو روی صفحه داشته باشه، زیرمجموعه ReactNode قرار می‌گیره. به تعریف تایپ اون در هسته ری‌آکت نگاه کنید:
type ReactNode = ReactElement | string | number | Iterable<ReactNode> | ReactPortal | boolean | null | undefined;
همون‌طور که می‌بینید، یک ReactNode می‌تونه یک آبجکت ری‌اکتی، یک متن ساده، یک عدد، آرایه‌ای از المان‌ها، یا حتی مقادیر خالی مثل null و undefined باشه.
// تمام موارد زیر به عنوان ReactNode کاملاً معتبر هستند:
const nodeText: React.ReactNode = "یک متن ساده";
const nodeNumber: React.ReactNode = 1405;
const nodeElement: React.ReactNode = <div>یک المان کامپوننت</div>;
const nodeNull: React.ReactNode = null;
کجا از کدوم استفاده کنیم؟
الان که با ماهیت هرکدوم آشنا شدیم، بیاید ببینیم در پروژه‌های واقعی (مخصوصا موقع تعریف ابزارهای کاستوم و پروژه‌های تیمی) بهترین انتخاب کدوم میشه.
سناریوی اول: تعریف فیلد children در کامپوننت‌ها (Best Practice: ReactNode)
اگر در حال ساخت یک کامپوننتِ Wrapper مثل دکمه‌های عمومی، Layout اصلی سایت یا کامپوننت‌های Card هستید که قراره محتوای مختلفی درون خودش جا بده، همیشه از ReactNode استفاده کنید. این کار به بقیه برنامه‌نویسها اجازه میده تا هر چیزی (از متن ساده تا چند تگ تو در تو) رو داخل کامپوننت شما بفرستند:
type LayoutProps = {
  children: React.ReactNode; // بهترین انتخاب برای دریافت هر نوع محتوا
};

export default function Layout({ children }: LayoutProps) {
  return <main className="main-container">{children}</main>;
}
سناریوی دوم: محدود کردن خروجی به تگ‌های ساختاریافته (Best Practice: ReactElement)
تصور کنید در حال ساخت کامپوننتی به نام List هستید و می‌خواید کاربر فقط و فقط تگ‌های <ListItem /> رو به عنوان فرزند ارسال کنه و اجازه نداشته باشه رشته متنی ساده یا عدد خالی بفرسته. در این سناریو، ReactElement انتخاب بهتری هست:
type ListProps = {
  // کاربر نمی‌تواند متن ساده بفرستد، حتماً باید یک کامپوننت یا تگ معتبر باشد
  children: React.ReactElement; 
};
سناریوی سوم: تایپ‌دهی خروجی توابع یا هوک‌های کاستوم (Best Practice: JSX.Element)
اگر متدی نوشتید که وظیفه‌ش تولید و برگردوندن یک قطعه کد HTML یا کامپوننت هستش، تعیین JSX.Element به عنوان تایپ خروجی، خوانایی کد شما رو بالا می‌بره و مشخص می‌کنه که خروجی این تابع یک سینتکس JSX هستش:
const renderStatusIcon = (status: string): JSX.Element => {
  if (status === "success") return <SuccessIcon />;
  return <ErrorIcon />;
};
جمع‌بندی
انتخاب درست بین این سه تایپ، بستگی به میزان سخت‌گیری یا انعطاف‌پذیری لازم در کدهای شما داره. اگر دنبال انعطاف زیاد برای رندر انواع داده‌ها باشید، ReactNode انتخاب خوبیه. اما اگر می‌خواید ساختار رو محدود به آبجکت‌های معتبر طراحی UI کنید، ReactElement و JSX.Element بهترین گزینه‌ها هستن.
شما در پروژه‌های خودتون بیشتر با کدوم‌ از این تایپ‌ها سر و کار دارید؟ تا حالا به خاطر استفاده جابجا از اون‌ها به باگ‌های تایپ‌اسکریپتی خوردید؟ تجربیات خودتون رو در بخش نظرات با ما در میون بذارید!
کامنت جدید

برای ثبت کامنت وارد شوید

برای اینکه بتوانید زیر این پست کامنت بگذارید، باید وارد حساب کاربری خود شوید.

برای ادامه، وارد حساب خود شوید

بعد از ورود، دوباره به همین پست برمی‌گردید و می‌توانید کامنتتان را ثبت کنید.

ورود به حساب
کامنت‌ها

نظرات کاربران

دیدگاه‌هایی که برای این نوشته ثبت شده‌اند.

هنوز کامنتی برای این پست ثبت نشده است.