React به‌عنوان Library در برابر Framework

در درس‌های قبل این فصل، قطعه‌های یک برنامه واقعی را جدا جدا دیدیم: Build Tool، Routing، دریافت داده، Styling، State، تست و Deployment. حالا یک پرسش بزرگ‌تر مطرح است که همه این تصمیم‌ها را به هم وصل می‌کند: آیا این قطعه‌ها را خودمان کنار هم می‌گذاریم و فقط از React به‌عنوان Library استفاده می‌کنیم، یا از یک Framework می‌خواهیم که آن‌ها را از پیش یکپارچه کرده باشد؟

تفاوت Library و Framework چیست

تفاوت اصلی در این است که چه کسی جریان اجرای برنامه را کنترل می‌کند. در یک Library، شما کد خودتان را می‌نویسید و در جاهایی که لازم است، توابع Library را صدا می‌زنید. در یک Framework، ساختار کلی برنامه از قبل تعیین شده است و Framework کد شما را (در جاهای تعیین‌شده) صدا می‌زند. به این وارونگی کنترل، Inversion of Control می‌گویند، و گاهی با جمله «ما شما را صدا می‌زنیم، شما ما را صدا نزنید» خلاصه می‌شود.

React خودش یک Library است

در صفحه اصلی مستندات رسمی، React به‌عنوان «کتابخانه‌ای برای رابط‌های کاربری وب و موبایل» معرفی می‌شود. React کامپوننت، State، Effect و رندر را فراهم می‌کند، اما درباره Routing، دریافت داده، ساختار فایل‌ها یا نحوه Build هیچ تصمیمی نمی‌گیرد. شکل مرسوم راه‌اندازی آن، همان چیزی است که در درس ۲۵-۱ دیدیم:

jsx
// main.jsx — شما React را راه‌اندازی می‌کنید
import { createRoot } from "react-dom/client";
import App from "./App.jsx";

createRoot(document.getElementById("root")).render(<App />);

در Framework، جهت صدا زدن برعکس می‌شود

jsx
// app/products/page.js — نمونه قرارداد Next.js App Router
export default async function ProductsPage() {
  const products = await db.products.findAll();
  return <ProductList products={products} />;
}

در این فایل هیچ createRoot ای نیست. Framework از روی نام و محل فایل می‌فهمد این صفحه مربوط به مسیر /products است، آن را پیدا می‌کند، روی سرور اجرا می‌کند و نتیجه را به مرورگر می‌فرستد. شما فقط یک کامپوننت بر اساس قرارداد تعریف کرده‌اید. این همان نقش Framework در Server Components است که در درس ۲۴-۸ دیدیم.

مثال مینیاتوری: Framework چگونه شما را صدا می‌زند

برای حس کردن این وارونگی، یک «Framework» بسیار کوچک می‌سازیم: تابعی که یک فهرست مسیر و کامپوننت می‌گیرد و خودش نوار ناوبری و انتخاب صفحه را مدیریت می‌کند. کد «شما» فقط صفحه‌ها را تعریف می‌کند. این یک ابزار آموزشی است، نه یک Framework واقعی.

یک Framework مینیاتوری و وارونگی کنترل
import { useState } from "react";

// «Framework»: مالک ساختار برنامه و ناوبری است
function createMiniApp(routes) {
  return function MiniApp() {
    const [path, setPath] = useState("/");
    const Page = routes[path];

    return (
      <div>
        <nav>
          {Object.keys(routes).map((p) => (
            <button key={p} onClick={() => setPath(p)}>
              {p}
            </button>
          ))}
        </nav>
        <Page />
      </div>
    );
  };
}

// کد «شما»: فقط صفحه‌ها را تعریف می‌کنید
function Home() {
  return <p>این صفحه خانه است.</p>;
}

function About() {
  return <p>این صفحه درباره ماست.</p>;
}

const MiniApp = createMiniApp({ "/": Home, "/about": About });

function App() {
  return <MiniApp />;
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

توجه کنید که در کد شما هیچ State ناوبری و هیچ نوار دکمه‌ای نیست؛ آن‌ها را MiniApp ساخته و صفحه‌های شما را صدا می‌زند. Frameworkهای واقعی همین ایده را در مقیاسی بسیار بزرگ‌تر (با Routing کامل، رندر سرور، Build و کش) اجرا می‌کنند.

آنچه یک برنامه واقعی علاوه بر React نیاز دارد

در درس ۲۵-۱ دیدیم مستندات React درباره Create React App این کمبودها را صریح گفته بود: راه‌حل از پیش برای Routing، دریافت داده و Code Splitting ندارد. هر کدام را در این فصل دیدیم. مقایسه دو مسیر:

نیاز مسیر Library + Build Tool مسیر Framework
Build و Dev Server خودتان انتخاب می‌کنید (مثلاً Vite) همراه Framework، از پیش پیکربندی‌شده
Routing کتابخانه جداگانه، پیکربندی دستی داخلی و معمولاً مبتنی بر ساختار فایل‌ها
دریافت داده Server State دستی یا کتابخانه (درس ۲۵-۳) Loader یا Server Component، متصل به Route
Code Splitting خودتان با lazy (فصل ۲۰) معمولاً خودکار بر اساس Route
رندر سرور و Streaming تنظیم دستی و پیچیده داخلی
Deployment معمولاً استاتیک و ساده (درس ۲۵-۷) بسته به شکل رندر، ممکن است محیط اجرا بخواهد

مزایا و هزینه‌های مسیر Library

  • مزایا: انعطاف کامل، هر قطعه قابل تعویض است، مدل ذهنی ساده برای یک SPA، و انتشار معمولاً فقط فایل استاتیک.
  • هزینه‌ها: خودتان باید قطعه‌ها را انتخاب، یکپارچه و نگه‌داری کنید؛ تصمیم‌های بیشتر یعنی احتمال ناهماهنگی بین اعضای تیم؛ و مشکلاتی مثل رندر سرور را باید خودتان حل کنید.

مزایا و هزینه‌های مسیر Framework

  • مزایا: راه‌حل‌های یکپارچه و آزموده‌شده، پیش‌فرض‌های خوب برای کارایی، و دسترسی عملی به Server Components و Streaming.
  • هزینه‌ها: یادگیری قراردادهای خود Framework (که مفاهیم React نیستند)، وابستگی بلندمدت به یک انتخاب، تغییرهای نسخه‌ای که ممکن است کد را بشکنند، و در بعضی حالت‌ها نیاز به یک محیط اجرای سروری.

مستندات رسمی React هم همین جمع‌بندی را دارد: برای ساختن یک برنامه یا سایت کامل با React، پیشنهاد می‌شود یکی از Frameworkهای مبتنی بر React انتخاب شود. در عین حال، گزینه ساختن از صفر با Build Tool هم در مستندات هست؛ پس هیچ‌کدام ممنوع نیست.

چند سوءبرداشت رایج

  • «Framework یعنی سریع‌تر»: نه الزاماً. Framework ابزار می‌دهد، ولی سرعت واقعی به نحوه استفاده بستگی دارد (همان درس فصل سیزدهم: اول اندازه بگیرید).
  • «SPA منسوخ شده»: خیر. برای برنامه‌ای پشت ورود کاربر (مثل داشبورد داخلی) که SEO و نمایش سریع محتوای اولیه برایش مهم نیست، یک SPA ساده کاملاً معتبر است.
  • «با Framework دیگر React یاد نمی‌گیرم»: برعکس: همه مفاهیم این دوره (State، Effect، Context، Suspense) همان‌طور در Framework هم کار می‌کنند؛ Framework فقط قراردادهای اضافه روی آن‌ها می‌گذارد، همان تفکیک «React در برابر Framework» که در درس ۲۴-۸ دیدیم.
  • «Library یعنی بدون ساختار»: هنوز هم باید ساختار پوشه‌ها، قرارداد نام‌گذاری و تصمیم‌های معماری را خودتان تعیین کنید؛ فقط کسی آن را برایتان از پیش تعیین نکرده است.

طیف، نه دو دسته جدا

این دو مسیر نقطه‌های دو سر یک طیف هستند. نمونه خوبش را در درس ۲۵-۲ دیدیم: React Router در حالت Declarative یک Library ساده است، در حالت Data امکان Loader و Action اضافه می‌کند، و در حالت Framework یک خط Build و رندر سرور هم دارد. بسیاری از Frameworkها حالت‌های Static Export یا SPA هم پشتیبانی می‌کنند. همچنین React را می‌توان به‌صورت تدریجی داخل یک صفحه موجود (مثلاً صفحه‌ای که با یک بک‌اند سنتی ساخته شده) اضافه کرد، بدون بازنویسی کل سایت.

سؤال‌های تصمیم‌گیری

  • آیا محتوای عمومی و موتور جست‌وجو یا سرعت نمایش اولیه مهم است؟ (به نفع Framework)
  • آیا برنامه عمدتاً پشت ورود کاربر و تعاملی است؟ (SPA ساده می‌تواند کافی باشد)
  • آیا تیم تجربه یکی از Frameworkها را دارد، یا ابزار مشخصی را قبلاً در سازمان استفاده می‌کند؟
  • آیا محدودیت میزبانی دارید (مثلاً فقط فایل استاتیک)؟ این روی گزینه‌های Framework اثر می‌گذارد.
  • آیا هدف یادگیری ساختار برنامه React از پایه است؟ (شروع با Build Tool ساده آموزنده‌تر است)

یک قاعده عملی

مثل درس‌های ۱۳ و ۱۶، قاعده این است: ساده‌ترین گزینه‌ای را انتخاب کنید که نیاز امروز و نیازهای نزدیک و مشخص آینده را برآورده می‌کند. پیچیدگی را پیشاپیش و بدون دلیل اضافه نکنید، ولی نیازهایی را هم که از همین حالا مشخص‌اند (مثل SEO یا رندر سرور) نادیده نگیرید، چون مهاجرت بعدی هزینه‌بر است.

جمع‌بندی

Library یعنی شما کد را می‌نویسید و ابزار را صدا می‌زنید؛ Framework یعنی ساختار از قبل تعیین شده و Framework کد شما را صدا می‌زند. React خودش یک Library است و Routing، دریافت داده و Build را تعیین نمی‌کند؛ Frameworkهای مبتنی بر آن این قطعه‌ها را یکپارچه می‌کنند. هر مسیر مزایا و هزینه‌های خودش را دارد: انعطاف و سادگی در برابر یکپارچگی و پیش‌فرض‌های آماده. این دو یک طیف‌اند، SPA منسوخ نشده، و مفاهیم React در هر دو یکی است. در درس بعدی، همه معیارهای این فصل را برای انتخاب ابزار بر اساس نیاز جمع‌بندی می‌کنیم.