Context در برابر Prop Drilling: چه زمانی کدام را انتخاب کنیم

تا اینجا در این فصل، Context را عمدتاً به‌عنوان راه‌حل مشکل Prop Drilling معرفی کردیم. اما این به این معنا نیست که Context همیشه انتخاب بهتری نسبت به عبور دادن مقدار از طریق Props است. در این درس، این دو رویکرد را مستقیماً مقایسه می‌کنیم تا مشخص شود هرکدام دقیقاً کجا مناسب‌ترند.

یادآوری مشکل اصلی Prop Drilling

همان‌طور که در درس اول این فصل دیدیم، Prop Drilling زمانی رخ می‌دهد که یک مقدار باید از میان چند کامپوننت میانی عبور کند، در حالی که آن کامپوننت‌های میانی هیچ استفاده‌ای از آن مقدار ندارند و فقط آن را منتقل می‌کنند.

Props همچنان انتخاب پیش‌فرض است

با وجود مشکل Prop Drilling، Props باید همچنان به‌عنوان روش پیش‌فرض برای انتقال داده در نظر گرفته شود؛ به چند دلیل مهم:

  • مسیر داده در Props کاملاً واضح و قابل ردیابی است؛ با نگاه کردن به یک کامپوننت، دقیقاً می‌بینیم چه Propsی از کجا می‌آید.
  • Props کامپوننت را مستقل‌تر نگه می‌دارد؛ کامپوننتی که فقط Props دریافت می‌کند، در جاهای مختلف با مقادیر متفاوت به‌راحتی قابل استفاده مجدد است.
  • همان‌طور که در درس قبل دیدیم، Context با هر تغییر مقدار، همه مصرف‌کنندگان را دوباره رندر می‌کند؛ در حالی که Props این اثر گسترده را ندارند.

چه زمانی Prop Drilling واقعاً مشکل‌ساز می‌شود

Prop Drilling همیشه بد نیست؛ عبور دادن یک Prop از میان یک یا دو لایه میانی، معمولاً کاملاً قابل قبول و حتی خواناتر از معرفی یک Context جدید است. این موضوع زمانی به یک مشکل واقعی تبدیل می‌شود که تعداد لایه‌های میانی زیاد باشد، یا وقتی همان مقدار، باید از میان بسیاری از شاخه‌های مختلف درخت کامپوننت‌ها (نه فقط یک مسیر خطی) عبور کند.

یک قاعده عملی برای تصمیم‌گیری

پیش از رفتن سراغ Context، می‌توان از این سؤالات استفاده کرد:

  • آیا این مقدار واقعاً باید در بسیاری از نقاط مختلف و دور از هم درخت کامپوننت‌ها در دسترس باشد؟
  • آیا تعداد لایه‌های میانی که فقط این مقدار را منتقل می‌کنند، به‌طور محسوسی زیاد است؟
  • آیا این مقدار به اندازه‌ای پایدار است که تغییرش، رندرهای گسترده ناشی از Context را توجیه کند؟

اگر پاسخ بیشتر این سؤالات مثبت است، Context گزینه مناسبی است. اگر مقدار فقط بین چند کامپوننت نزدیک به هم رد و بدل می‌شود، Props همچنان ساده‌تر و واضح‌تر است.

یک راه‌حل میانی: ترکیب کامپوننت‌ها به‌جای Context

گاهی، آنچه در نگاه اول شبیه Prop Drilling به نظر می‌رسد، در واقع با تغییر ساختار کامپوننت‌ها و استفاده از الگوی children (که در فصل دوم دیدیم) قابل حل است، بدون نیاز به Context:

// به‌جای رد کردن user از چند لایه
function Layout({ user }) {
  return (
    <div>
      <Sidebar user={user} />
    </div>
  );
}

// می‌توان کامپوننت آماده را مستقیماً به‌جای Layout پاس داد
function App() {
  const user = { name: "سارا" };
  return (
    <Layout>
      <Sidebar user={user} />
    </Layout>
  );
}

function Layout({ children }) {
  return <div>{children}</div>;
}

در این نسخه، Layout دیگر لازم نیست چیزی درباره user بداند؛ چون Sidebar از قبل، با تمام Propsهایش، در جای درست ساخته شده و فقط به‌عنوان children رد می‌شود.

مثال قابل اجرا

مقایسه Prop Drilling ساده و استفاده از children
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Props باید همچنان روش پیش‌فرض انتقال داده باشد، چون مسیر داده را واضح نگه می‌دارد و کامپوننت‌ها را مستقل‌تر می‌کند. Context زمانی مناسب است که یک مقدار واقعاً در بخش‌های زیاد و دور از هم برنامه لازم باشد و عبور دستی آن از میان چند لایه، خوانایی را کاهش دهد. در درس بعدی، به این می‌پردازیم که دقیقاً چه زمانی استفاده از Context توصیه می‌شود.