مفاهیمی که باید در React اونا رو بدونین (بعد از یادگیری مقدماتی) - قسمت 3 - کار با React Context API

دسته بندی: آموزش
زمان مطالعه: 8 دقیقه
۲۴ دی ۱۳۹۷

مفاهیمی که باید در React اونا رو بدونین (بعد از یادگیری مقدماتی) - قسمت 2در این قسمت میخوام مطلب مفاهیمی که باید در React اونا رو بدونین رو ادامه بدم و اطلاعات بیشتری رو در مورد مفاهیم React در اختیارتون قرار بدم.

در جلسه قبل در مورد Higher-order component و نحوه استفاده از State و مدیریت State در component توضیح دادیم و با نحوه عملکرد اونا آشنا شدیم. در این  جلسه میخوام آخرین مفهوم که React Context Api هست رو توضیح بدم.

4. React Context Api

همونطور که میدونین برای اینکه اطلاعاتی رو از component پدر به component فرزند پاس بدیم، میتونیم از props‌ها استفاده کنیم و در component فرزند به اون دسترسی داشته باشیم. بعضی از اطلاعات و props‌ها هستند که در بیشتر component‌ها به اونا نیاز داریم و اینکه بخوایم اونا رو تک تک به همه component‌ها به عنوان props پاس بدیم خیلی کار دست و پا گیر و زمانبری هست. برای مثال میشه theme و locale یا زبان رو جزء این props‌ها در نظر گرفت.

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

پس همونطور که میبینید برای پاس دادن اطلاعات به component‌های پایین‌تر، باید props‌های زیادی رو قرار بدین و اگر یک روزی به این نتیجه رسیدید که دیگه به این props نیاز ندارید، باید همه اون props‌ها رو از همه component‌ها پاک کنید و کار زمانبر و سختی هست.

اینجا هست که Context Api خودش رو نشون میده و به کمک ما میاد. Context یک راه در اختیار ما قرار میده که اطلاعات مورد نظرمون رو بین component‌ها به اشتراک بزاریم، بدون اینکه نیاز باشه props رو تک تک در درخت component‌ها پاس بدیم.

چه زمانی از Context استفاده کنیم؟

Context برای به اشتراک‌گذاری اطلاعات بین درختی از component‌های React طراحی شده است. برخی از این اطلاعات که بیشتر از اونا استفاده میشه عبارتند از:

  • کاربر Authenticate شده فعلی (برای سایت‌هایی که login و signup دارند)
  • تم یا Theme انتخابی (برای سایت‌هایی که استایلهای متنوعی دارند و توسط کاربر مشخص میشه)
  • زبان انتخابی (برای سایت‌های چند زبانه)

اول میخوام یک مثال بزنم و دنیای قبل از Context رو بررسی کنم. مثال زیر رو ببینید:

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}

class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />;
  }
}

در مثال بالا میخوایم یک props به نام theme رو از App به ThemedButton پاس بدیم. پس در ابتدا باید اون رو به component میانی Toolbar پاس بدیم و بعد از اون در Toolbar اون رو به ThemedButton پاس بدیم تا بتونیم از اون استفاده کنیم. این کار دو مشکل داره.

  • مشکل اول اینه که اصلا به theme در Toolbar نیاز نیست و فقط نقش واسطه رو داره و حالا اگر به جای اینجا که 2 سطح هست، 10 سطح بود، باید این props رو برای همه اونا رو قرار میدادیم تا به component آخر برسه. اینکار باعث میشه هم اطلاعات اضافی و غیرضروری در کدها قرار بگیره و هم اینکه در صورت مشکل باید همه این component‌ها رو تغییر بدیم و وقت زیادی از ما میگیره.
  • مشکل دوم اینه که اگر بخوایم برای هر Button به این صورت یک theme رو قرار بدیم، خیلی دردسر داره چون زیاد از Button در سایت استفاده میشه و اینکه بخوایم اینکار رو انجام بدیم واقعا وقت زیادی رو از ما میگیره و Refactor کردن کدها دشوار میشه.

حالا اگر بخوایم همین مثال بالا رو با استفاده از Context Api انجام بدیم و چیزی رو به component میانی پاس ندیم، بصورت زیر عمل خواهیم کرد:

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  static contextType = ThemeContext;

  render() {
    return <Button theme={this.context} />;
  }
}

همونطور که میبینید در خط 1 با استفاده از متد createContext یک Context رو با نام ThemeContext به وجود آوردیم و مقدار اولیه light رو برای اون در نظر گرفتیم. همونطور که میبینید در App از این ThemeContext و ویژگی Provider اون استفاده شده و از اون به عنوان parent کامپوننت Toolbar استفاده شده است. همچنین با استفاده از ویژگی value مقدار فعلی context رو از light به dark تبدیل کردیم. با این کار Toolbar و همه component‌ها فرزند اون به این Context دسترسی دارند و دیگه نیازی نیست که props‌ها رو بصورت تک تک بین component‌ها دست به دست کنیم.

در ThemedButton میخوایم از این Context استفاده کنیم. با استفاده از ContextType میتونیم context مورد نظرمون رو به component معرفی کنیم. حالا یک ویژگی context در اختیارتون قرار میگیره که میتونین از اون در هر جای component که بخواید استفاده کنید. پس در اینجا this.context همون مقدار dark خواهد بود.

بررسی دقیق‌تر API

React.createContext:

Syntax استفاده از این متد بصورت زیر هست:

const MyContext = React.createContext(defaultValue);

این متد یک شئ Context رو میسازه. زمانی که در یکی از Component‌ها از Subscribe استفاده میکنید و Context مورد نظرتون رو مشخص میکنید، React نزدیکترین Provider که در درخت Component‌ها و در بالای اون قرار داده شده رو انتخاب میکنه.

مقدار defaultValue فقط زمانی مورد استفاده قرار میگیره که component نتونه Provider مورد نظر رو در بالای درخت یا tree خودش پیدا بکنه. زمانی که مقدار undefined رو برای defaultValue قرار میدین، component‌ها دیگه در صورت پیدا نکردن Provider این مقدار undefined رو مصرف یا consume نمیکنن.

Context.Provider:

هر شئ Context دارای یک React component به نام Provider هست که میتونین component هایی که قصد دارید در اونا از این Context استفاده کنید رو در این Provider قرار بدین و از این به بعد همه Component‌های فرزند Provider به تغییرات Context دسترسی دارند.

Syntax استفاده از Provider بصورت زیر هست:

<MyContext.Provider value={/* some value */}>
  {/* some components */}
</MyContext.Provider>

شما با استفاده از value میتونین مقدار مورد نظرتون برای context رو مشخص کنید تا component هایی که در زیر این Provider قرار دارند، از این value به عنوان context استفاده کنند. یک Provider میتونه همزمان به چند Consumer متصل بشه. شما میتونین از Provider‌ها بصورت تودرتو استفاده کنید و مقادیر مربوط به Context رو در سطح مورد نظرتون تغییر بدین.

Class.contextType:

Syntax استفاده از این ویژگی بصورت زیر می‌باشد:

class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* perform a side-effect at mount using the value of MyContext */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* render something based on the value of MyContext */
  }
}

MyClass.contextType = MyContext;

همونطور که در خط آخر میبینید، ویژگی contextType مربوط به Class رو برابر با MyContext قرار دادم. با این کار این Component از Context مورد نظر استفاده میکنه و شما میتونین با استفاده از this.context به مقدار فعلی context دسترسی داشته باشید و در هر جایی از Component که بخواید از اون استفاده کنید. با این Syntax فقط میتونین به یک Context متصل بشید.

اگر شما از babel و پلاگین transform-class-properties اون استفاده میکنید، میتونین بجای استفاده از روش بالا برای تعریف Context، بصورت زیر عمل کنید:

class MyClass extends React.Component {
  static contextType = MyContext;

  render() {
    let value = this.context;
    /* render something based on the value */
  }
}

همونطور که میبینید یک ویژگی static تعریف کردیم و MyContext رو درونش قرار دادم. با این کار همانند قبل میتونیم از this.context برای دسترسی به مقدار فعلی Context استفاده کنیم.

Context.Consumer:

Syntax استفاده از این Component بصورت زیر هست:

<MyContext.Consumer>
  {value => /* render something based on the context value */}
</MyContext.Consumer>

با استفاده از این Component میتونین به یک Context متصل بشید و به تغییرات اون Subscribe کنید. از این مورد میتونین هم در Class base component و هم در functional component استفاده کنید.

این Component یک تابع رو به عنوان فرزند یا Child قبول میکنه. این تابع مقدار فعلی Context رو به عنوان ورودی دریافت میکنه و یک React node رو برگشت میده.

برای مطالعه بیشتر در مورد React Context Api میتونین مستندات مربوط به React رو مطالعه کنید.

نتیجه‌گیری

همونطور که دیدید Context Api میتونه خیلی از مشکلات رو برطرف کنه و اطلاعات رو بین Component‌های مورد نظرمون به اشتراک بزاره.

در این سه قسمت از مفاهیمی که باید در React اونا رو بدونین، سعی شد چیزایی که هر توسعه‌دهنده React نیاز هست که اونا رو بدونه رو در اختیارتون قرار بدیم.

چه امتیازی به این مقاله می دید؟
نویسنده محمد اسفندیاری
بسیار به طراحی وب علاقمندم و به سرعت در حال یادگیری تمام مباحث پیشرفته هستم و دوست دارم که به دیگران هم یاد بدهم.

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

اولین دیدگاه این پست رو تو بنویس !

ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :