مقدمه

تاکنون، تنها راه ما برای اشتراک‌گذاری داده بین کامپوننت‌ها، ارسال props از والد به فرزند بوده است. این روش برای کامپوننت‌هایی که نزدیک به هم هستند به خوبی کار می‌کند. اما تصور کنید یک اپلیکیشن بزرگ دارید که در آن، یک state تعریف شده در کامپوننت سطح بالا، باید توسط یک کامپوننت در عمق زیادی از درخت کامپوننت‌ها استفاده شود.

در این حالت، ما مجبوریم prop را از طریق تمام کامپوننت‌های میانی (که خودشان به آن prop نیازی ندارند) عبور دهیم تا به کامپوننت مقصد برسد. به این الگوی نامطلوب، «حفاری پراپ» یا Prop Drilling گفته می‌شود. این کار کد را شلوغ کرده و نگهداری آن را دشوار می‌کند.

راه‌حل: React Context

React Context API یک راه حل برای مشکل prop drilling ارائه می‌دهد. Context به شما اجازه می‌دهد تا داده‌هایی را که «سراسری» (global) در نظر گرفته می‌شوند (مانند اطلاعات کاربر لاگین کرده، تم اپلیکیشن، یا زبان انتخابی) را بدون نیاز به پاس دادن دستی props در هر سطح، در اختیار تمام کامپوننت‌های زیرمجموعه خود قرار دهید.

سه مرحله اصلی کار با Context

  1. ایجاد Context: با استفاده از createContext()، یک شیء context ایجاد می‌کنیم.
  2. فراهم کردن Context: کامپوننت‌های خود را با یک Context Provider احاطه کرده و داده‌ای را که می‌خواهیم به اشتراک بگذاریم، به prop مربوط به value آن پاس می‌دهیم.
  3. استفاده از Context: هر کامپوننت فرزندی در این زیردرخت، می‌تواند با استفاده از هوک useContext، به این داده دسترسی پیدا کند.

یک مثال کاربردی

بیایید یک مثال ساده برای مدیریت تم تیره/روشن با استفاده از Context بسازیم.

۱. ایجاد ThemeContext

ابتدا، یک فایل جدید به نام ThemeContext.js ایجاد کرده و کد زیر را در آن قرار می‌دهیم:

Copy Icon ThemeContext.js
import { createContext } from 'react';

export const ThemeContext = createContext('light');

این کد یک context جدید به نام ThemeContext ایجاد می‌کند که مقدار پیش‌فرض آن 'light' است.

۲. فراهم کردن Context در کامپوننت والد

حالا در کامپوننت اصلی اپلیکیشن (مثلاً App.js)، از ThemeContext.Provider برای فراهم کردن مقدار تم استفاده می‌کنیم.

Copy Icon App.js
import { ThemeContext } from './ThemeContext';
import Toolbar from './Toolbar';

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

در اینجا، ما کامپوننت Toolbar (و تمام فرزندان آن) را با ThemeContext.Provider احاطه کرده و مقدار 'dark' را به عنوان value فراهم کرده‌ایم.

۳. استفاده از Context در کامپوننت فرزند

حالا هر کامپوننت فرزندی، هرچقدر هم که در عمق قرار داشته باشد، می‌تواند با هوک useContext به این مقدار دسترسی پیدا کند.

Copy Icon JAVASCRIPT (React)
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return (
    <button style={{ background: theme === 'dark' ? 'black' : 'white' }}>
      I am styled by theme context!
    </button>
  );
}

کامپوننت ThemedButton با useContext(ThemeContext) نزدیک‌ترین value فراهم شده توسط یک Provider در بالای خود را می‌خواند و از آن برای استایل‌دهی استفاده می‌کند.

در این درس، با React Context به عنوان یک راه‌حل قدرتمند برای مشکل prop drilling آشنا شدیم. دیدیم که چگونه می‌توان با استفاده از Provider و هوک useContext داده‌های سراسری را به صورت کارآمد در اختیار یک درخت از کامپوننت‌ها قرار داد.

Context یک ابزار عالی برای داده‌هایی است که به ندرت تغییر می‌کنند. اما اگر بخواهیم یک state پیچیده را به همراه منطق به‌روزرسانی آن به صورت سراسری به اشتراک بگذاریم چه؟ در درس بعدی، به «ترکیب useReducer با useContext» خواهیم پرداخت و خواهیم دید که چگونه می‌توان با ترکیب این دو هوک، یک الگوی مدیریت وضعیت بسیار قدرتمند و مقیاس‌پذیر ایجاد کرد.