انتخاب ابزار مناسب بر اساس نیاز

این درس، درس آخر بخش آموزشی فصل بیست‌وپنجم است. در درس‌های قبل، ابزارها را یکی‌یکی دیدیم: Build Tool، Routing، دریافت داده، Styling، State، تست، Deployment، و تفاوت Library با Framework. اینجا همه را در یک روش تصمیم‌گیری جمع می‌کنیم: به‌جای پرسیدن «بهترین ابزار کدام است؟»، می‌پرسیم «نیاز من چیست و کدام ابزار آن را با کمترین هزینه برآورده می‌کند؟». درس ۱۶-۶ همین کار را فقط برای State کرد؛ این‌جا کل برنامه را در نظر می‌گیریم.

چرا «بهترین ابزار» سؤال بدی است

در همین فصل چند نمونه دیدیم که نشان می‌دهد اکوسیستم چقدر سریع تغییر می‌کند: Create React App برای پروژه‌های جدید منسوخ شد (درس ۲۵-۱)، بسته react-router-dom در نسخه ۸ حذف شد (درس ۲۵-۲)، styled-components به حالت نگه‌داری رفت (درس ۲۵-۴)، و Recoil متوقف شد (درس ۲۵-۵). ابزاری که امروز «بهترین» است، ممکن است سه سال بعد انتخاب مناسبی نباشد. پس بهتر است تصمیم را بر پایه نیاز و معیارهای پایدار بگیریم، نه ترند.

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

  1. محتوا برای چه کسی و از کجا است؟ اگر محتوا عمومی است و موتورهای جست‌وجو یا نمایش سریع اولیه مهم‌اند، به رندر سمت سرور یا تولید استاتیک نیاز دارید (به نفع Framework). اگر برنامه پشت ورود کاربر است و SEO مهم نیست، یک SPA ساده کافی است. (درس‌های ۲۴-۱، ۲۵-۸)
  2. چه نوع میزبانی در دسترس است؟ اگر فقط فایل استاتیک می‌توانید منتشر کنید، رندر با هر درخواست روی سرور ممکن نیست. (درس ۲۵-۷)
  3. Routing چه شکلی لازم است؟ Layoutهای تودرتو، Loader و دریافت داده متصل به Route معمولاً به Routing یکپارچه با Framework نزدیک می‌شوند؛ یک SPA ساده با Router Declarative هم کافی است. (درس ۲۵-۲)
  4. داده از کجا می‌آید و چقدر تعاملی است؟ داده اولیه صفحه را در Server Component یا Loader بخوانید؛ برای داده تعاملی و پرتغییر، کتابخانه Server State. (درس‌های ۲۴-۶ و ۲۵-۳)
  5. چه Client State واقعاً Global است؟ با State محلی شروع کنید، بعد Context و useReducer، و فقط در صورت نشانه واقعی سراغ Zustand، Redux Toolkit و مانند آن بروید. (درس‌های ۱۶-۳ و ۲۵-۵)
  6. چقدر طراحی اختصاصی و دسترس‌پذیری لازم است؟ این روی انتخاب Styling و کتابخانه UI (آماده، Headless یا کپی‌شونده) اثر می‌گذارد. (درس ۲۵-۴)
  7. تست و انتشار چگونه است؟ Test Runner، React Testing Library، MSW و E2E، با CI/CD قبل از هر انتشار. (درس‌های ۲۵-۶ و ۲۵-۷)

شش سناریوی نمونه

سناریو جهت‌گیری منطقی دلیل
داشبورد داخلی پشت ورود SPA با Build Tool ساده، Router ساده، کتابخانه Server State، میزبانی استاتیک SEO و رندر سرور ضرورتی ندارد؛ ساده و ارزان
وبلاگ یا سایت محتوایی Framework با تولید استاتیک و Server Component محتوا عمومی و کم‌تغییر؛ نیازی به سرور زنده نیست
فروشگاه یا سایت عمومی با داده پویا Framework با رندر سرور و Streaming SEO و نمایش سریع مهم‌اند و محتوا به درخواست وابسته است
برنامه بسیار تعاملی (ویرایشگر، ابزار طراحی) بیشتر Client؛ State سبک و اتمیک، ابزارهای فصل ۱۳ و ۲۲ برای کارایی بیشتر عمر برنامه در تعامل مرورگر می‌گذرد
برنامه موبایل Frameworkی با پشتیبانی React Native (مثلاً Expo) مستندات رسمی React آن را برای برنامه‌های Native توصیه می‌کند
نمونه آزمایشی یا یادگیری Vite با React، بدون Router و بدون Store در ابتدا کمترین پیچیدگی؛ بعداً در صورت نیاز اضافه کنید

این جدول فقط جهت‌گیری اولیه است، نه حکم. اگر سازمان شما از قبل ابزار مشخصی دارد، یا تیم به یک Framework مسلط است، همین دو عامل می‌توانند تصمیم را عوض کنند.

هزینه تغییر: چه چیزهایی را باید بیشتر مراقب بود

همه تصمیم‌ها به یک اندازه سخت برگشت‌پذیر نیستند. یک تقسیم‌بندی تقریبی:

هزینه تغییر نمونه تصمیم‌ها
بالا Framework، سیستم Routing، کتابخانه UI استایل‌دار
متوسط کتابخانه Server State، کتابخانه Client State، رویکرد Styling
پایین‌تر Test Runner، ابزار تحلیل بسته، پلتفرم میزبانی (معمولاً)

برای تصمیم‌های پرهزینه، وقت بیشتری بگذارید و یک نمونه کوچک واقعی بسازید. برای تصمیم‌های ارزان‌تر، سریع‌تر و با ریسک کمتر انتخاب کنید. این همان درس هزینه وابستگی بلندمدت است که در درس ۱۶-۴ دیدیم.

چک‌لیست ارزیابی یک ابزار

  • نگه‌داری فعال: آخرین انتشار، سرعت پاسخ به مشکلات، و وضعیت رسمی پروژه (فعال، حالت نگه‌داری، متوقف).
  • سازگاری با نسخه React شما: بررسی کنید با نسخه فعلی (و در صورت لزوم، Server Components) سازگار است یا نه.
  • سربار: حجم اضافه به بسته مرورگر (درس ۲۰-۳) و پیچیدگی اضافه.
  • مستندات و جامعه: آیا مشکل رایج، پاسخ مشخصی دارد؟
  • راه خروج: اگر روزی لازم شد جایگزینش کنید، چقدر کد وابسته آن شده است؟
  • دسترس‌پذیری و RTL: برای برنامه فارسی، پشتیبانی راست‌به‌چپ و رعایت اصول فصل ۱۸ را در مستندات بررسی کنید.

اشتباه‌های رایج در انتخاب

  • انتخاب به‌خاطر ترند: «همه از آن استفاده می‌کنند» یک نیاز نیست.
  • پیچیدگی از روز اول: اضافه کردن Store سراسری، Framework و چند کتابخانه پیش از وجود مشکل، همان بهینه‌سازی زودهنگام است که در فصل ۱۳ دیدیم.
  • ابزار بیش از حد: هر ابزار، هزینه یادگیری، به‌روزرسانی و ناسازگاری احتمالی دارد؛ تعدادشان را تا حد نیاز نگه دارید.
  • نادیده گرفتن تیم: بهترین ابزار روی کاغذ، اگر کسی در تیم بلد نباشد، هزینه واقعی دارد.
  • تصمیم‌های جدا از هم: انتخاب Routing، دریافت داده و Framework به هم گره خورده‌اند؛ آن‌ها را هماهنگ بگیرید.

تصمیم، یک بار برای همیشه نیست

می‌توان با ساده‌ترین گزینه شروع کرد و در صورت ظهور نشانه‌های واقعی (کندی، تکرار منطق، نیاز به SEO) ارتقا داد. برای کاهش هزینه ارتقا، می‌توان منطق وابسته به یک کتابخانه را پشت یک تابع یا Hook نازک خودتان نگه داشت (مثلاً یک Custom Hook مثل useProduct که داخلش از هر کتابخانه‌ای استفاده کند، فصل ۱۰). البته این هم هزینه دارد؛ آن را فقط برای ابزارهایی انجام دهید که در سراسر برنامه استفاده می‌شوند و احتمال تعویضشان واقعی است.

مثال قابل اجرا: راهنمای تصمیم

در این مثال، یک «راهنمای تصمیم» کوچک ساخته‌ایم. سه گزینه را علامت بزنید و جهت‌گیری پیشنهادی را ببینید. توجه کنید که پیشنهاد در State جداگانه ذخیره نشده، بلکه در هر رندر از روی سه مقدار محاسبه می‌شود: همان اصل Derived State فصل سوم.

راهنمای ساده تصمیم‌گیری برای انتخاب معماری
import { useState } from "react";

function recommend({ seo, dynamic, server }) {
  if (!seo) {
    return "SPA با یک Build Tool ساده (مثلاً Vite)؛ Framework اختیاری است.";
  }
  if (!dynamic) {
    return "Framework با تولید استاتیک؛ سرور زنده لازم نیست.";
  }
  if (server) {
    return "Framework با رندر سرور یا Server Components.";
  }
  return "تعارض: رندر سرور با هر درخواست، سرور زنده می‌خواهد. یا بخش پویا را در کلاینت بگیرید یا میزبانی را عوض کنید.";
}

function App() {
  const [answers, setAnswers] = useState({
    seo: false,
    dynamic: false,
    server: false,
  });

  function toggle(key) {
    setAnswers((current) => ({ ...current, [key]: !current[key] }));
  }

  const recommendation = recommend(answers);

  return (
    <div>
      <label>
        <input type="checkbox" checked={answers.seo} onChange={() => toggle("seo")} />
        محتوای عمومی که باید در موتور جست‌وجو دیده شود
      </label>
      <br />
      <label>
        <input type="checkbox" checked={answers.dynamic} onChange={() => toggle("dynamic")} />
        محتوا برای هر کاربر یا هر درخواست فرق می‌کند
      </label>
      <br />
      <label>
        <input type="checkbox" checked={answers.server} onChange={() => toggle("server")} />
        امکان اجرای یک سرور زنده دارم
      </label>
      <p><strong>جهت‌گیری پیشنهادی:</strong> {recommendation}</p>
    </div>
  );
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

انتخاب ابزار باید از نیاز شروع شود، نه از ترند: محتوا و SEO، شکل میزبانی، Routing، دریافت داده، Client State، Styling و UI، و در نهایت تست و انتشار. سناریوهای مختلف جهت‌گیری‌های متفاوتی دارند، و تصمیم‌های پرهزینه‌تر (Framework، Routing، کتابخانه UI) توجه بیشتری می‌خواهند. معیارهای ارزیابی (نگه‌داری فعال، سازگاری با نسخه، سربار، راه خروج، دسترس‌پذیری و RTL) از ابزارهایی که سریع منسوخ می‌شوند ایمن‌ترند. ساده شروع کنید، نشانه‌های واقعی را دنبال کنید و فقط در صورت نیاز ارتقا دهید. با این درس، بخش آموزشی فصل بیست‌وپنجم پایان می‌یابد و در ادامه به آزمون فصل ۲۵ می‌رویم.