الفرق بين المراجعتين لصفحة: «React/context»

من موسوعة حسوب
لا ملخص تعديل
تحديث
 
(4 مراجعات متوسطة بواسطة 3 مستخدمين غير معروضة)
سطر 24: سطر 24:
}
}


function ThemedButton(props) {
class ThemedButton extends React.Component {
  return <Button theme={props.theme} />;
  render() {
    return <Button theme={this.props.theme} />;
  }
}
}
</syntaxhighlight>نتجنب باستخدام السياق تمرير الخاصيات عبر عناصر وسيطة:<syntaxhighlight lang="javascript">
</syntaxhighlight>نتجنب باستخدام السياق تمرير الخاصيات عبر عناصر وسيطة:<syntaxhighlight lang="javascript">
// يُتيح لنا السياق تمرير القيمة بعمق شجرة المكونات
// يُتيح لنا السياق تمرير القيمة بعمق شجرة المكونات
سطر 49: سطر 50:


// لا يجب على المكون الموجود في الوسط أن يمرر القالب للمستويات الأدنى منه
// لا يجب على المكون الموجود في الوسط أن يمرر القالب للمستويات الأدنى منه
function Toolbar(props) {
function Toolbar() {
   return (
   return (
     <div>
     <div>
سطر 57: سطر 58:
}
}


function ThemedButton(props) {
class ThemedButton extends React.Component {
   // استخدام Consumer لقراءة سياق القالب الحالي
   // استخدام Consumer لقراءة سياق القالب الحالي
   // ستبحث React عن أقرب Provider للقالب في المستوى الأعلى منها وتستخدم قيمته
   // ستبحث React عن أقرب Provider للقالب في المستوى الأعلى منها وتستخدم قيمته
   // في هذا المثال قيمة القالب الحالي هي "dark"
   // في هذا المثال قيمة القالب الحالي هي "dark"
    
    
    
   static contextType = ThemeContext;
   return (
   render() {
     <ThemeContext.Consumer>
     return <Button theme={this.context} />;
      {theme => <Button {...props} theme={theme} />}
   }
    </ThemeContext.Consumer>
   );
}
}
</syntaxhighlight>
</syntaxhighlight>


سطر 90: سطر 88:
</syntaxhighlight>قد يبدو من الفائض تمرير الخاصيّات <code>user</code> و <code>avatarSize</code> عبر مستويات عديدة للأسفل إن كان يحتاجه في النهاية فقط المكوّن <code>Avatar</code>. من المزعج أيضًا كلّما احتاج المُكوِّن <code>Avatar</code> المزيد من الخاصيّات من المستويات الأعلى فيجب عليك إضافتها في كل المستويات الوسيطة أيضًا.
</syntaxhighlight>قد يبدو من الفائض تمرير الخاصيّات <code>user</code> و <code>avatarSize</code> عبر مستويات عديدة للأسفل إن كان يحتاجه في النهاية فقط المكوّن <code>Avatar</code>. من المزعج أيضًا كلّما احتاج المُكوِّن <code>Avatar</code> المزيد من الخاصيّات من المستويات الأعلى فيجب عليك إضافتها في كل المستويات الوسيطة أيضًا.


من طرق حل هذه المشكلة بدون السياق هي ت<nowiki/>[[React/composition vs inheritance#.D9.85.D9.81.D9.87.D9.88.D9.85 .D8.A7.D9.84.D8.A7.D8.AD.D8.AA.D9.88.D8.A7.D8.A1|مرير المكون <code>Avatar</code> نفسه للأسفل]] بحيث لا تحتاج المكوّنات الوسيطة أن تعلم حول الخاصيّة <code>user</code>:<syntaxhighlight lang="javascript">
من طرق حل هذه المشكلة بدون السياق هي ت<nowiki/>[[React/composition vs inheritance#.D9.85.D9.81.D9.87.D9.88.D9.85 .D8.A7.D9.84.D8.A7.D8.AD.D8.AA.D9.88.D8.A7.D8.A1|مرير المكون <code>Avatar</code> نفسه للأسفل]] بحيث لا تحتاج المكوّنات الوسيطة أن تعلم حول الخاصيّتين <code>avatarSize</code> أو <code>user</code>:<syntaxhighlight lang="javascript">
function Page(props) {
function Page(props) {
   const user = props.user;
   const user = props.user;
سطر 101: سطر 99:
}
}


// Now, we have:
// لدينا الآن:
<Page user={user} />
<Page user={user} avatarSize={avatarSize} />
// ... والذي يصير ...
// ... والذي يصير ...
<PageLayout userLink={...} />
<PageLayout userLink={...} />
سطر 132: سطر 130:
   );
   );
}
}
</syntaxhighlight>يكفينا هذا النمط للعديد من الحالات عند الحاجة لفصل مكوّن ابن عن المكونات الآباء له. وبإمكانك أخذ هذا إلى أبعد من ذلك عن طريق [[React/render props|خاصيّات التصيير]] إن كان المكوّن الابن يحتاج إلى التواصل مع المكوّن الأب قبل التصيير.
</syntaxhighlight>يكفينا هذا النمط للعديد من الحالات عند الحاجة لفصل مكوّن ابن عن المكونات الآباء له. وبإمكانك أخذ هذا إلى أبعد من ذلك عن طريق [[React/render props|خاصيّات التصيير]] إن كان المكوّن الابن يحتاج إلى التواصل مع المكوّن الأب قبل التصيير.


سطر 141: سطر 138:
=== <code>React.createContext</code> ===
=== <code>React.createContext</code> ===
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
const {Provider, Consumer} = React.createContext(defaultValue);
const MyContext = React.createContext(defaultValue);
 
</syntaxhighlight>يُنشِئ الزوج <code>{ Provider, Consumer }</code>.


عند تصيير React للسياق <code>Consumer</code> فستقرأ قيمة السياق الحالية من أقرب مُزوِّد <code>Provider</code> فوقها في الشجرة.
</syntaxhighlight>عند تصيير React لمكون من كائن السياق، فستقرأ قيمة السياق الحالية من أقرب مُزوِّد <code>Provider</code> فوقها في الشجرة.


يُستخدَم الوسيط <code>defaultValue</code> عن طريق المستهلك <code>Consumer</code> فقط عندما لا يجد مزوّد <code>Provider</code> مُطابِق فوقه في الشجرة. يُفيد هذا من أجل اختبار المُكوّنات على انفراد بدون تغليفها.
لا يُستخدَم الوسيط <code>defaultValue</code> إلا في حال لم يُعثَر على مزوّد <code>Provider</code> مُطابِق فوقه في الشجرة. يُفيد هذا من أجل اختبار المُكوّنات على انفراد بدون تغليفها.


ملاحظة: لا يُؤدّي تمرير القيمة <code>undefined</code> كقيمة للمُزوِّد إلى استخدام المستهلك <code>Consumer</code> للقيمة <code>defaultValue</code>.
ملاحظة: لا يُؤدّي تمرير القيمة <code>undefined</code> كقيمة للمُزوِّد إلى جعل المكون يستخدم <code>defaultValue</code>.


=== المزود <code>Provider</code> ===
=== المزود <code>Provider</code> ===
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
<Provider value={/* قيمة ما */}>
<MyContext.Provider value={/* قيمة ما */}>


</syntaxhighlight>وهو مُكوِّن React الذي يسمح للمستهلك <code>Consumer</code> بأن يُشارك في تغييرات السياق.
</syntaxhighlight>يأتي كل كائن سياق مع مُكوِّن React مزود الذي يسمح للمكون المستهلِك بأن يُشارك في تغييرات السياق.


يقبل خاصيّة للقيمة <code>value</code> لتمريرها إلى المستهلكات المنحدرة عن هذا المُزوِّد. يُمكِن وصل مُزوِّد واحد مع العديد من المستهلكات. يُمكِن مداخلة المُزوِّدات لتجاوز قيم عميقة ضمن شجرة المُكوِّنات.
يقبل خاصيّة للقيمة <code>value</code> لتمريرها إلى المستهلكات المنحدرة عن هذا المُزوِّد. يُمكِن وصل مُزوِّد واحد مع العديد من المستهلكات. يُمكِن مداخلة المُزوِّدات لتجاوز قيم عميقة ضمن شجرة المُكوِّنات.
جميع المكونات المستهلكة المنحدرة من المزوّد ستصيَّر كلما تغيرت قيمة الخاصية <code>value</code> الخاصة بالمزود. لا تخضع عملية الانتشار من المزود إلى المكونات المستهلكة التابعة له (بما في ذلك <code>contextType</code> و <code>useContext</code>) للتابع <code>shouldComponentUpdate</code> ، لذلك يُحدّث المكون المستهلك حتى عندما يتخطى أحد المكونات الأصلية تحديثًا.
تُحدّد التغييرات عبر مقارنة القيم الجديدة والقديمة باستخدام نفس الخوارزمية التي تستخدمها مثل <code>Object.is</code>.
'''ملاحظة''': يمكن أن تسبّب الطريقة التي يتم بها تحديد التغييرات بعض المشاكل عند تمرير الكائنات كقيمة.
<code>Class.contextType</code><syntaxhighlight lang="javascript">
class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* MyContext تنفيذ تأثير جانبي عند الوصل باستعمال قيمة */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* MyContext تصيير شيء اعتمادًا على قيمة */
  }
}
MyClass.contextType = MyContext;
</syntaxhighlight>يمكن إسناد الخاصية <code>contextType</code> في أي صنف إلى كائن سياق (Context object) أنشئ بوساطة <code>()React.createContext</code>. يمكِّنك ذلك من استهلاك أقرب قيمة حالية لنوع ذلك السياق باستعمال <code>this.context</code>. تستطيع الإشارة عبر مرجع إلى هذا في أي تابع من توابع دورة الحياة بما فيها الدالة <code>render</code>.
ملاحظة: تستطيع الاشتراك في سياق وحيد باستعمال الواجهة البرمجية هذه. إن احتجت إلى قراءة المزيد من أكثر من سياق واحد، اطلع على القسم "[[React/context#.D8.A7.D8.B3.D8.AA.D9.87.D9.84.D8.A7.D9.83 .D8.B3.D9.8A.D8.A7.D9.82.D8.A7.D8.AA .D9.85.D8.AA.D8.B9.D8.AF.D8.AF.D8.A9|استهلاك سياقات متعددة]]".
إن كنت تستخدم صياغة حقول الصنف العامة ([https://babeljs.io/docs/plugins/transform-class-properties/ public class fields syntax]) التجريبية، تستطيع استعمال حقل صنف ساكن (static class field) لتهيئة نوع السياق <code>contextType</code> الخاص بك.<syntaxhighlight lang="javascript">
class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    /* value صيّر شيئًا بناءً على القيمة */
  }
}
</syntaxhighlight>


=== المستهلك <code>Consumer</code> ===
=== المستهلك <code>Consumer</code> ===
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
<Consumer>
<MyContext.Consumer>
   {value => /* تصيير شيء ما اعتمادًا على قيمة السياق */}
   {value => /* تصيير شيء ما اعتمادًا على قيمة السياق */}
</Consumer>
</MyContext.Consumer>


</syntaxhighlight>وهو مُكوِّن React الذي يُشارِك بتغييرات السياق.
</syntaxhighlight>وهو مُكوِّن React الذي يُشارِك بتغييرات السياق داخل دوال المكونات.


يتطلّب [[React/render props|دالة كابن له]]. تستقبل الدالة قيمة السياق الحاليّة وتُعيد عقدة React. تكون قيمة الوسيط <code>value</code> المُمرَّرة إلى الدالة مساوية للخاصيّة <code>value</code> لأقرب مُزوِّد لهذا السياق في المستويات الأعلى من الشجرة. إن لم يُوجَد مُزوِّد لهذا السياق في المستوى الأعلى، ستكون قيمة الوسيط <code>value</code> مساوية للقيمة <code>defaultValue</code> التي مرّرناها للتابع <code>createContext()‎</code>.
يتطلّب [[React/render props|دالة كابن له]]. تستقبل الدالة قيمة السياق الحاليّة وتُعيد عقدة React. تكون قيمة الوسيط <code>value</code> المُمرَّرة إلى الدالة مساوية للخاصيّة <code>value</code> لأقرب مُزوِّد لهذا السياق في المستويات الأعلى من الشجرة. إن لم يُوجَد مُزوِّد لهذا السياق في المستوى الأعلى، ستكون قيمة الوسيط <code>value</code> مساوية للقيمة <code>defaultValue</code> التي مرّرناها للتابع <code>createContext()‎</code>.
سطر 176: سطر 211:


ملاحظة: قد تُسبِّب طريقة التغييرات المُحدَّدة بعض المشاكل عند تمرير الكائنات في الوسيط <code>value</code>: سنتحدّث عن المزيد في [[React/context#.D9.85.D8.AD.D8.A7.D8.B0.D9.8A.D8.B1|قسم المحاذير]].
ملاحظة: قد تُسبِّب طريقة التغييرات المُحدَّدة بعض المشاكل عند تمرير الكائنات في الوسيط <code>value</code>: سنتحدّث عن المزيد في [[React/context#.D9.85.D8.AD.D8.A7.D8.B0.D9.8A.D8.B1|قسم المحاذير]].
=== <code>Context.Consumer</code> ===
<syntaxhighlight lang="javascript">
<MyContext.Consumer>
  {value => /* صيّر شيئًا بناء على قيمة السياق */}
</MyContext.Consumer>
</syntaxhighlight>يتغير مكون React الذي يشترك بسياق، وهذا يمكِّنك من الاشتراك بسياق ضمن [[React/components and props#.D9.85.D9.83.D9.88.D9.86.D8.A7.D8.AA .D8.A7.D9.84.D8.A3.D8.B5.D9.86.D8.A7.D9.81 .D9.88.D8.A7.D9.84.D8.AF.D9.88.D8.A7.D9.84|مكون دالة.]]
تتطلب الخاصية <code>Consumer</code> [[React/render props#.D8.A7.D8.B3.D8.AA.D8.AE.D8.AF.D8.A7.D9.85 .D8.AE.D8.A7.D8.B5.D9.8A.D8.A7.D8.AA .D8.A3.D8.AE.D8.B1.D9.89 .D8.BA.D9.8A.D8.B1 render|دالةً على أنَّها ابنٌ]]، إذ تستقبل هذه الدالة قيمة السياق الحالي وتعيد عقدة React. الوسيط <code>value</code> المُمرَّر إلى الدالة سيكون مساويًّا إلى قيمة الخاصية <code>value</code> لأقرب مزود (Provider) لهذا السياق في الشجرة أعلاه. إن لم يكن هنالك مزود (Provider) لهذا السياق أعلاه، فسيكون الوسيط <code>value</code> مساويًا إلى القيمة <code>defaultValue</code> التي مُرِّرت إلى <code>()createContext</code>.
ملاحظة: للمزيد من المعلومات حول النمط "دالة على أنَّها ابنٌ"، اطلع على توثيق [[React/render props|خاصيات التصيير]].
=== <code>Context.displayName</code> ===
يقبل كائن السياق خاصية نصية <code>displayName</code>. تستخدم أداة React DevTools قيمة هذه الخاصية لتحديد ما سيتم عرضه في السياق.
على سبيل المثال، قيمة المكون المعروضة في المثال التالي ستكون <code>MyDisplayName</code> في DevTools:<syntaxhighlight lang="javascript">
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
</syntaxhighlight>


== أمثلة ==
== أمثلة ==


=== السياق الديناميكي ===
=== السياق الديناميكي ===
هذه أمثلة أكثر تعقيدا تكون فيها قيم القالب ديناميكية:


==== theme-context.js ====
==== <code>theme-context.js</code> ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
export const themes = {
export const themes = {
سطر 200: سطر 258:
</syntaxhighlight>
</syntaxhighlight>


==== themed-button.js ====
==== <code>themed-button.js</code> ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
import {ThemeContext} from './theme-context';
import {ThemeContext} from './theme-context';


function ThemedButton(props) {
class ThemedButton extends React.Component {
   return (
   render() {
     <ThemeContext.Consumer>
     let props = this.props;
      {theme => (
    let theme = this.context;
        <button
    return (
          {...props}
      <button
          style={{backgroundColor: theme.background}}
        {...props}
        />
        style={{backgroundColor: theme.background}}
 
      />
      )}
    );
    </ThemeContext.Consumer>
   }
   );
}
}
ThemedButton.contextType = ThemeContext;


export default ThemedButton;
export default ThemedButton;
سطر 222: سطر 280:
</syntaxhighlight>
</syntaxhighlight>


==== app.js ====
==== <code>app.js</code> ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
import {ThemeContext, themes} from './theme-context';
import {ThemeContext, themes} from './theme-context';
سطر 231: سطر 289:
   return (
   return (
     <ThemedButton onClick={props.changeTheme}>
     <ThemedButton onClick={props.changeTheme}>
       تغيير القالب
       Change Theme
     </ThemedButton>
     </ThemedButton>
   );
   );
سطر 254: سطر 312:


   render() {
   render() {
// يستخدم الزر ThemedButton بداخل المزود ThemeProvider
// يستخدم الزر ThemedButton بداخل المزود ThemeProvider
// القالب من الحالة بينما يستخدم الموجود بالخارج القالب الافتراضي dark
// القالب من الحالة بينما يستخدم الموجود بالخارج القالب الافتراضي dark
سطر 276: سطر 335:
من الضروري أحيانًا تحديث السياق من المكون المتداخل بعمق في مكانٍ ما من شجرة المكونات. في هذه الحالة تستطيع تمرير دالة إلى الأسفل عبر السياق للسماح للمستهلكات بتحديث السياق:
من الضروري أحيانًا تحديث السياق من المكون المتداخل بعمق في مكانٍ ما من شجرة المكونات. في هذه الحالة تستطيع تمرير دالة إلى الأسفل عبر السياق للسماح للمستهلكات بتحديث السياق:


==== theme-context.js ====
==== <code>theme-context.js</code> ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
// التأكد من أنّ القيمة الافتراضية الممررة
// التأكد من أنّ القيمة الافتراضية الممررة
سطر 287: سطر 346:
</syntaxhighlight>
</syntaxhighlight>


==== theme-toggler-button.js ====
==== <code>theme-toggler-button.js</code> ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
import {ThemeContext} from './theme-context';
import {ThemeContext} from './theme-context';
سطر 299: سطر 358:
           onClick={toggleTheme}
           onClick={toggleTheme}
           style={{backgroundColor: theme.background}}>
           style={{backgroundColor: theme.background}}>
           إطفاء أو تشغيل القالب
           Toggle Theme
         </button>
         </button>
       )}
       )}
سطر 307: سطر 366:


export default ThemeTogglerButton;
export default ThemeTogglerButton;
</syntaxhighlight>
</syntaxhighlight>


==== app.js ====
==== <code>app.js</code> ====
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
import {ThemeContext, themes} from './theme-context';
import {ThemeContext, themes} from './theme-context';
سطر 335: سطر 393:
     };
     };
   }
   }
  render() {
// تمرر كامل الحالة إلى المزود
     return (
     return (
       <ThemeContext.Provider value={this.state}>
       <ThemeContext.Provider value={this.state}>
سطر 355: سطر 410:


ReactDOM.render(<App />, document.root);
ReactDOM.render(<App />, document.root);
  render() {
// تمرر كامل الحالة إلى المزود


</syntaxhighlight>
</syntaxhighlight>
سطر 371: سطر 431:
   render() {
   render() {
     const {signedInUser, theme} = this.props;
     const {signedInUser, theme} = this.props;
// مكون التطبيق الذي يزودنا بقيم مبدئية للسياق
// مكون التطبيق الذي يزودنا بقيم مبدئية للسياق
     return (
     return (
سطر 409: سطر 468:
</syntaxhighlight>إن كانت قيمة سياقين أو أكثر مستخدمة معًا، فقد ترغب بالنظر إلى إنشاء مكون خاصية التصيير الخاص بك والذي يزودك بكليهما معًا.
</syntaxhighlight>إن كانت قيمة سياقين أو أكثر مستخدمة معًا، فقد ترغب بالنظر إلى إنشاء مكون خاصية التصيير الخاص بك والذي يزودك بكليهما معًا.


=== الوصول إلى السياق في توابع دورة الحياة ===
== محاذير Caveats ==
إن الوصول للقيم من السياق في توابع دورة الحاية هو حالة استخدام شائعة نسبيًّا. وبدلًا من إضافة سياق لكل تابع دورة حياة فستحتاج فقط إلى تمريرها كخاصيّة ومن ثمّ العمل معها كما تتعامل عادة مع الخاصيّات:<syntaxhighlight lang="javascript">
class Button extends React.Component {
  componentDidMount() {
// قيمة ThemeContext هي this.props.theme
  }
 
  componentDidUpdate(prevProps, prevState) {
// قيمة ThemeContext السابقة هي prevProps.theme
// قيمة ThemeContext الجديدة هي this.props.theme
  }
 
  render() {
    const {theme, children} = this.props;
    return (
      <button className={theme || 'light'}>
        {children}
      </button>
    );
  }
}
 
export default props => (
  <ThemeContext.Consumer>
    {theme => <Button {...props} theme={theme} />}
  </ThemeContext.Consumer>
);
 
</syntaxhighlight>
 
=== استهلاك السياق باستخدام المكونات ذات الترتيب الأعلى ===
تُستهلَك بعض أنواع السياقات عن طريق العديد من المكوِّنات (مثل القالب أو تفضيلات اللغة). قد يكون من البديهي تغليف كل اعتمادية بعنصر <code><Context.Consumer></code>. قد تُساعدنا [[React/higher order components|المكوّنات ذات الترتيب الأعلى]] هنا.
 
على سبيل المثال قد يستهلك مكوّن الزر سياق القالب كما يلي:<syntaxhighlight lang="javascript">
const ThemeContext = React.createContext('light');
 
function ThemedButton(props) {
  return (
    <ThemeContext.Consumer>
      {theme => <button className={theme} {...props} />}
    </ThemeContext.Consumer>
  );
}
 
</syntaxhighlight>قد يكون هذا صحيحًا بالنسبة لبعض المكوّنات، ولكن ماذا لو أردنا استخدام سياق القالب في الكثير من الأماكن؟
 
يمكننا إنشاء مكوّن ذو ترتيب أعلى يُدعى <code>withTheme</code>:<syntaxhighlight lang="javascript">
const ThemeContext = React.createContext('light');
 
// تأخذ هذه الدالة مكون
export function withTheme(Component) {
  // وتعيد مكون آخر
  return function ThemedComponent(props) {
// وتصير المكون المغلف بقالب السياق
// لاحظ أننا مررنا أية خاصيات إضافية أيضًا
    return (
      <ThemeContext.Consumer>
        {theme => <Component {...props} theme={theme} />}
      </ThemeContext.Consumer>
    );
  };
}
 
</syntaxhighlight>يستطيع الآن أي مكوّن يعتمد على سياق القالب الاشتراك بسهولة إليه باستخدام الدالة <code>withTheme</code> التي أنشأناها:<syntaxhighlight lang="javascript">
function Button({theme, ...rest}) {
  return <button className={theme} {...rest} />;
}
 
const ThemedButton = withTheme(Button);
 
</syntaxhighlight>
 
=== تمرير المراجع لمستهلكات السياق ===
من مشاكل API خاصيّة التصيير هي عدم تمرير المراجع بشكل تلقائي للعناصر المُغلَّفة. وللالتفاف على هذه المشكلة استخدم <code>React.forwardRef</code>.
 
==== fancy-button.js ====
<syntaxhighlight lang="javascript">
lass FancyButton extends React.Component {
  focus() {
    // ...
  }
 
  // ...
}
 
// استخدم السياق لتمرير القالب الحالي إلى FancyButton
// استخدم forwardRef لتمرير المراجع إلى FancyButton أيضًا
export default React.forwardRef((props, ref) => (
  <ThemeContext.Consumer>
    {theme => (
      <FancyButton {...props} theme={theme} ref={ref} />
    )}
  </ThemeContext.Consumer>
));
 
</syntaxhighlight>
 
==== app.js ====
<syntaxhighlight lang="javascript">
import FancyButton from './fancy-button';
 
const ref = React.createRef();
 
// سيشير مرجعنا إلى المكون FancyButton
// وليس إلى ThemeContext.Consumer الذي يغلفه
// يعني هذا أنه يمكننا استدعاء توابع FancyButton مثل ref.current.focus()
<FancyButton ref={ref} onClick={handleClick}>
  اضغط هنا
</FancyButton>;
 
</syntaxhighlight>
 
== محاذير ==
بما أنّ السياق يستخدم هوية المرجع لتحديد وقت إعادة التصيير، فهنالك بعض الأشياء التي قد تُطلِق تصييرات غير مقصودة في المستهلكات <code>consumers</code> عندما يُعيد المُزوِّد <code>provider</code> الأب التصيير. على سبيل المثال ستُعيد الشيفرة التالية تصيير جميع المستهلكات في كل مرة يُعيد فيها المُزوّد التصيير، وذلك بسبب إنشاء كائن جديد دومًا للخاصيّة <code>value</code>:<syntaxhighlight lang="javascript">
بما أنّ السياق يستخدم هوية المرجع لتحديد وقت إعادة التصيير، فهنالك بعض الأشياء التي قد تُطلِق تصييرات غير مقصودة في المستهلكات <code>consumers</code> عندما يُعيد المُزوِّد <code>provider</code> الأب التصيير. على سبيل المثال ستُعيد الشيفرة التالية تصيير جميع المستهلكات في كل مرة يُعيد فيها المُزوّد التصيير، وذلك بسبب إنشاء كائن جديد دومًا للخاصيّة <code>value</code>:<syntaxhighlight lang="javascript">
class App extends React.Component {
class App extends React.Component {
   render() {
   render() {
     return (
     return (
       <Provider value={{something: 'something'}}>
       <MyContext.Provider value={{something: 'something'}}>
         <Toolbar />
         <Toolbar />
       </Provider>
       </MyContext.Provider>
     );
     );
   }
   }
}
}
</syntaxhighlight>ولكي تلتف على هذا احتفظ بقيمة <code>value</code> في حالة الأب:<syntaxhighlight lang="javascript">
</syntaxhighlight>ولكي تلتف على هذا احتفظ بقيمة <code>value</code> في حالة الأب:<syntaxhighlight lang="javascript">
class App extends React.Component {
class App extends React.Component {
سطر 550: سطر 496:
   }
   }
}
}
</syntaxhighlight>
</syntaxhighlight>


== واجهة برمجة التطبيقات القديمة ==
== واجهة برمجة التطبيقات القديمة ==
ملاحظة: كانت تأتي React سابقًا مع واجهة برمجة تطبيقات (API) تجريبية للسياق. ستبقى هذه الواجهة مدعومة في جميع الإصدارات <code>‎16.x</code>‎، ولكن يجب على التطبيقات التي تستخدمها أن تنتقل للإصدار الجديد. ستُزال هذه الواجهة القديمة في إصدار React المستقبلي الرئيسي. اقرأ توثيق السياق القديم [https://reactjs.org/docs/legacy-context.html من هنا].
'''ملاحظة''': كانت تأتي React سابقًا مع واجهة برمجة تطبيقات (API) تجريبية للسياق. ستبقى هذه الواجهة مدعومة في جميع الإصدارات <code>‎16.x</code>‎، ولكن يجب على التطبيقات التي تستخدمها أن تنتقل للإصدار الجديد. ستُزال هذه الواجهة القديمة في إصدار React المستقبلي الرئيسي. اقرأ توثيق السياق القديم [https://reactjs.org/docs/legacy-context.html من هنا].


== انظر أيضًا ==
* [[React/jsx in depth|شرح JSX بالتفصيل]]
* [[React/static type checking|التحقق من الأنواع الثابتة]]
* [[React/typechecking with proptypes|التحقق من الأنواع باستخدام PropTypes]]
* [[React/refs and the dom|استخدام المراجع مع DOM]]
* [[React/uncontrolled components|المكونات غير المضبوطة]]
* [[React/optimizing performance|تحسين الأداء]]
* [[React/react without es6|React بدون ES6]]
* [[React/react without jsx|React بدون JSX]]
* [[React/reconciliation|المطابقة (Reconciliation)]]
* [[React/fragments|استخدام الأجزاء (Fragments) في React]]
* [[React/portals|المداخل (Portals) في React]]
* [[React/error boundaries|حدود الأخطاء]]
* [[React/web components|مكونات الويب]]
* [[React/higher order components|المكونات ذات الترتيب الأعلى]]
* [[React/forwarding refs|تمرير المراجع]]
* [[React/render props|خاصيات التصيير]]
* [[React/integrating with other libraries|تكامل React مع المكتبات الأخرى]]
* [[React/accessibility|سهولة الوصول]]
* [[React/code splitting|تقسيم الشيفرة]]
* [[React/strict mode|الوضع الصارم (Strict Mode)]]
== مصادر==
== مصادر==
*[https://reactjs.org/docs/context.html صفحة استخدام السياق (Context) في React في توثيق React الرسمي].
*[https://reactjs.org/docs/context.html صفحة استخدام السياق (Context) في React في توثيق React الرسمي].
[[تصنيف:React]]
[[تصنيف:React]]
[[تصنيف:React Advanced Guides]]

المراجعة الحالية بتاريخ 11:29، 3 نوفمبر 2020

يُزوِّدنا السياق (Context) بطريقة لتمرير البيانات عبر شجرة المُكوّنات بدون الحاجة لتمرير الخاصيّات props يدويًّا من الأعلى للأسفل في كل مستوى.

تُمرَّر البيانات في تطبيقات React الاعتيادية من المستوى الأعلى للأسفل (أي من المكوّنات الآباء إلى المكوّنات الأبناء) عبر الخاصيّات props، ولكن قد يكون هذا بطيئًا لبعض أنواع الخاصيّات (مثل تفضيلات اللغة وقوالب واجهة المستخدم) والتي تحتاجها العديد من المكوّنات ضمن التطبيق. يُزوِّدنا السياق بطريقة لمشاركة القيم كتلك الموجودة بين المكوّنات بدون الاضطرار لتمرير الخاصيّات عبر كل مستوى من الشجرة.

متى نستخدم السياق

يكون السياق مُصمَّمًا لمشاركة البيانات التي تُعتبر عامّة (global) لشجرة مكوّنات React، مثل المستخدم قيد المصادقة حاليًّا، أو القالب، أو تفضيلات اللغة. على سبيل المثال في الشيفرة التالية نُمرِّر خاصيّة القالب (theme) يدويًّا من أجل تنسيق مكوّن الزر Button:

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

function Toolbar(props) {
  // يجب أن يأخذ مكون شريط الأدوات Toolbar خاصيّة theme إضافية
  // ويمررها إلى ThemedButton
  // قد يصبح هذا عملًا شاقًّا إن احتاج كل زر في التطبيق أن يعرف القالب theme
  // لأنه يجب تمريره عبر كل المكونات
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}

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

نتجنب باستخدام السياق تمرير الخاصيات عبر عناصر وسيطة:

// يُتيح لنا السياق تمرير القيمة بعمق شجرة المكونات
// بدون الحاجة إلى تمريره إلى كل مكون
// أنشئ السياق لأجل القالب الحالي (مع وضع القيمة light كقيمة افتراضية)
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
	// استخدم Provider لتمرير القالب الحالي إلى الشجرة التالية.
	// يستطيع أي مكون قراءة القالب الحالي بغض النظر عن مدى عمقه في شجرة المكونات
	// في هذا المثال نمرر "dark" كقيمة للقالب الحالي
	
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// لا يجب على المكون الموجود في الوسط أن يمرر القالب للمستويات الأدنى منه
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // استخدام Consumer لقراءة سياق القالب الحالي
  // ستبحث React عن أقرب Provider للقالب في المستوى الأعلى منها وتستخدم قيمته
  // في هذا المثال قيمة القالب الحالي هي "dark"
  
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

قبل أن تستخدم السياق

يُستخدَم السياق بشكل أساسي عند الحاجة للوصول إلى بعض البيانات من قبل العديد من المكونات في مستويات متداخلة مختلفة، ولكن لا يجب استخدامه بكثرة لأنّ يجعل من إعادة استخدام المكونات أمرًا أكثر صعوبة.

إن أردت فقط تجنّب تمرير بعض الخاصيّات عبر العديد من المستويات، فسيكون استخدام التراكيب حلًّا أبسط من استخدام السياق.

على سبيل المثال افترض وجود مكون للصفحة Page والذي يُمرِّر خاصيّات المستخدم user وحجم الصورة الرمزية avatarSize عبر مستويات عديدة للأسفل بحيث تتمكّن مكونات الرابط Link والصورة الرمزية Avatar الموجودة في مستويات عميقة ومتداخلة أن تقرأها:

<Page user={user} avatarSize={avatarSize} />
// ... والذي يصير ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... والذي يصير ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... والذي يصير ...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>

قد يبدو من الفائض تمرير الخاصيّات user و avatarSize عبر مستويات عديدة للأسفل إن كان يحتاجه في النهاية فقط المكوّن Avatar. من المزعج أيضًا كلّما احتاج المُكوِّن Avatar المزيد من الخاصيّات من المستويات الأعلى فيجب عليك إضافتها في كل المستويات الوسيطة أيضًا. من طرق حل هذه المشكلة بدون السياق هي تمرير المكون Avatar نفسه للأسفل بحيث لا تحتاج المكوّنات الوسيطة أن تعلم حول الخاصيّتين avatarSize أو user:

function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// لدينا الآن:
<Page user={user} avatarSize={avatarSize} />
// ... والذي يصير ...
<PageLayout userLink={...} />
// ... والذي يصير ...
<NavigationBar userLink={...} />
// ... والذي يصير ...
{props.userLink}

مع هذا التغيير يحتاج فقط المكون Page ذو المستوى الأعلى إلى أن يعرف عن استخدام المكوّنات Link و Avatar للمكوّنات user و avatarSize.

يؤدي قلب السيطرة هذا إلى جعل شيفرتك أبسط في العديد من الحالات عن طريق تقليل كمية الخاصيّات التي تحتاج تمريرها عبر تطبيقك ويُعطيك سيطرة أكبر على المكوّنات الجذريّة. على الرغم من ذلك لا يكون ذلك هو الخيار الأنسب في كل حالة، حيث أنّ نقل المزيد من التعقيد إلى مستوى أعلى في الشجرة يجعل من المكونات ذات المستوى الأعلى أكثر تعقيدًا ويجبر المكونات ذات المستويات الأدنى أن تكون مرنة أكثر مما قد ترغب.

لن تكون محدودًا بمكوّن ابن واحد، فبإمكانك تمرير مكونات أبناء متعددة أو حتى امتلاك منافذ منفصلة متعددة للأبناء كما هو موثق هنا:

function Page(props) {
  const user = props.user;
  const content = <Feed user={user} />;
  const topBar = (
    <NavigationBar>
      <Link href={user.permalink}>
        <Avatar user={user} size={props.avatarSize} />
      </Link>
    </NavigationBar>
  );
  return (
    <PageLayout
      topBar={topBar}
      content={content}
    />
  );
}

يكفينا هذا النمط للعديد من الحالات عند الحاجة لفصل مكوّن ابن عن المكونات الآباء له. وبإمكانك أخذ هذا إلى أبعد من ذلك عن طريق خاصيّات التصيير إن كان المكوّن الابن يحتاج إلى التواصل مع المكوّن الأب قبل التصيير.

على أية حال تحتاج بعض البيانات أحيانًا أن تكون قابلة للوصول من قبل العديد من المكوّنات في الشجرة، وبمستويات متداخلة مختلفة. يُتيح لك السياق نشر مثل هذه البيانات وتغييراتها إلى جميع المكوّنات في المستويات الأدنى. تتضمّن الأمثلة الشائعة التي يكون فيها استخدام السياق أبسط من البدائل هي إدارة اللغة الحالية، أو القالب، أو مخبأ البيانات (cache).

واجهة برمجة التطبيقات (API)

React.createContext

const MyContext = React.createContext(defaultValue);

عند تصيير React لمكون من كائن السياق، فستقرأ قيمة السياق الحالية من أقرب مُزوِّد Provider فوقها في الشجرة.

لا يُستخدَم الوسيط defaultValue إلا في حال لم يُعثَر على مزوّد Provider مُطابِق فوقه في الشجرة. يُفيد هذا من أجل اختبار المُكوّنات على انفراد بدون تغليفها.

ملاحظة: لا يُؤدّي تمرير القيمة undefined كقيمة للمُزوِّد إلى جعل المكون يستخدم defaultValue.

المزود Provider

<MyContext.Provider value={/* قيمة ما */}>

يأتي كل كائن سياق مع مُكوِّن React مزود الذي يسمح للمكون المستهلِك بأن يُشارك في تغييرات السياق.

يقبل خاصيّة للقيمة value لتمريرها إلى المستهلكات المنحدرة عن هذا المُزوِّد. يُمكِن وصل مُزوِّد واحد مع العديد من المستهلكات. يُمكِن مداخلة المُزوِّدات لتجاوز قيم عميقة ضمن شجرة المُكوِّنات.

جميع المكونات المستهلكة المنحدرة من المزوّد ستصيَّر كلما تغيرت قيمة الخاصية value الخاصة بالمزود. لا تخضع عملية الانتشار من المزود إلى المكونات المستهلكة التابعة له (بما في ذلك contextType و useContext) للتابع shouldComponentUpdate ، لذلك يُحدّث المكون المستهلك حتى عندما يتخطى أحد المكونات الأصلية تحديثًا.

تُحدّد التغييرات عبر مقارنة القيم الجديدة والقديمة باستخدام نفس الخوارزمية التي تستخدمها مثل Object.is.

ملاحظة: يمكن أن تسبّب الطريقة التي يتم بها تحديد التغييرات بعض المشاكل عند تمرير الكائنات كقيمة.

Class.contextType

class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* MyContext تنفيذ تأثير جانبي عند الوصل باستعمال قيمة */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* MyContext تصيير شيء اعتمادًا على قيمة */
  }
}
MyClass.contextType = MyContext;

يمكن إسناد الخاصية contextType في أي صنف إلى كائن سياق (Context object) أنشئ بوساطة ()React.createContext. يمكِّنك ذلك من استهلاك أقرب قيمة حالية لنوع ذلك السياق باستعمال this.context. تستطيع الإشارة عبر مرجع إلى هذا في أي تابع من توابع دورة الحياة بما فيها الدالة render.

ملاحظة: تستطيع الاشتراك في سياق وحيد باستعمال الواجهة البرمجية هذه. إن احتجت إلى قراءة المزيد من أكثر من سياق واحد، اطلع على القسم "استهلاك سياقات متعددة".

إن كنت تستخدم صياغة حقول الصنف العامة (public class fields syntax) التجريبية، تستطيع استعمال حقل صنف ساكن (static class field) لتهيئة نوع السياق contextType الخاص بك.

class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    /* value صيّر شيئًا بناءً على القيمة */
  }
}

المستهلك Consumer

<MyContext.Consumer>
  {value => /* تصيير شيء ما اعتمادًا على قيمة السياق */}
</MyContext.Consumer>

وهو مُكوِّن React الذي يُشارِك بتغييرات السياق داخل دوال المكونات.

يتطلّب دالة كابن له. تستقبل الدالة قيمة السياق الحاليّة وتُعيد عقدة React. تكون قيمة الوسيط value المُمرَّرة إلى الدالة مساوية للخاصيّة value لأقرب مُزوِّد لهذا السياق في المستويات الأعلى من الشجرة. إن لم يُوجَد مُزوِّد لهذا السياق في المستوى الأعلى، ستكون قيمة الوسيط value مساوية للقيمة defaultValue التي مرّرناها للتابع createContext()‎.

ملاحظة: للمزيد من المعلومات حول النمط "دالة كابن" انظر إلى صفحة خاصيّة التصيير.

كل المستهلكات Consumers المنحدرة عن المُزوِّد ستُعيد التصيير عندما تتغير قيمة الخاصيّة value للمُزوّد. لا يخضع الانتشار من المُزوّد إلى المستهلكات المنحدرة عنه إلى التابع shouldComponentUpdate، لذا يُحدَّث المستهلك حتى ولو كان المكوّن الأب غير خاضع للتحديث.

تُحدَّد التغييرات عن طريق مقارنة القيم الجديدة والقديمة باستخدام نفس الخوارزمية مثل Object.is.

ملاحظة: قد تُسبِّب طريقة التغييرات المُحدَّدة بعض المشاكل عند تمرير الكائنات في الوسيط value: سنتحدّث عن المزيد في قسم المحاذير.

Context.Consumer

<MyContext.Consumer>
  {value => /* صيّر شيئًا بناء على قيمة السياق */}
</MyContext.Consumer>

يتغير مكون React الذي يشترك بسياق، وهذا يمكِّنك من الاشتراك بسياق ضمن مكون دالة.

تتطلب الخاصية Consumer دالةً على أنَّها ابنٌ، إذ تستقبل هذه الدالة قيمة السياق الحالي وتعيد عقدة React. الوسيط value المُمرَّر إلى الدالة سيكون مساويًّا إلى قيمة الخاصية value لأقرب مزود (Provider) لهذا السياق في الشجرة أعلاه. إن لم يكن هنالك مزود (Provider) لهذا السياق أعلاه، فسيكون الوسيط value مساويًا إلى القيمة defaultValue التي مُرِّرت إلى ()createContext.

ملاحظة: للمزيد من المعلومات حول النمط "دالة على أنَّها ابنٌ"، اطلع على توثيق خاصيات التصيير.

Context.displayName

يقبل كائن السياق خاصية نصية displayName. تستخدم أداة React DevTools قيمة هذه الخاصية لتحديد ما سيتم عرضه في السياق.

على سبيل المثال، قيمة المكون المعروضة في المثال التالي ستكون MyDisplayName في DevTools:

const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';

<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools

أمثلة

السياق الديناميكي

هذه أمثلة أكثر تعقيدا تكون فيها قيم القالب ديناميكية:

theme-context.js

export const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee',
  },
  dark: {
    foreground: '#ffffff',
    background: '#222222',
  },
};

export const ThemeContext = React.createContext(
  themes.dark // القيمة الافتراضية
);

themed-button.js

import {ThemeContext} from './theme-context';

class ThemedButton extends React.Component {
  render() {
    let props = this.props;
    let theme = this.context;
    return (
      <button
        {...props}
        style={{backgroundColor: theme.background}}
      />
    );
  }
}
ThemedButton.contextType = ThemeContext;

export default ThemedButton;

app.js

import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';

// مكون وسيط يستخدم ThemedButton
function Toolbar(props) {
  return (
    <ThemedButton onClick={props.changeTheme}>
      Change Theme
    </ThemedButton>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: themes.light,
    };

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };
  }

  render() {

	// يستخدم الزر ThemedButton بداخل المزود ThemeProvider
	// القالب من الحالة بينما يستخدم الموجود بالخارج القالب الافتراضي dark
    return (
      <Page>
        <ThemeContext.Provider value={this.state.theme}>
          <Toolbar changeTheme={this.toggleTheme} />
        </ThemeContext.Provider>
        <Section>
          <ThemedButton />
        </Section>
      </Page>
    );
  }
}

ReactDOM.render(<App />, document.root);

تحديث السياق من المكونات المتداخلة

من الضروري أحيانًا تحديث السياق من المكون المتداخل بعمق في مكانٍ ما من شجرة المكونات. في هذه الحالة تستطيع تمرير دالة إلى الأسفل عبر السياق للسماح للمستهلكات بتحديث السياق:

theme-context.js

// التأكد من أنّ القيمة الافتراضية الممررة
// إلى createContext تطابق الشكل الذي يتوقعه المستخدم
export const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () => {},
});

theme-toggler-button.js

import {ThemeContext} from './theme-context';

function ThemeTogglerButton() {
  // لا يستقبل زر تغيير القالب قيمة القالب فقط وإنما الدالة toggleTheme من السياق أيضا
  return (
    <ThemeContext.Consumer>
      {({theme, toggleTheme}) => (
        <button
          onClick={toggleTheme}
          style={{backgroundColor: theme.background}}>
          Toggle Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

export default ThemeTogglerButton;

app.js

import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

	// تحتوي الحالة أيضًا على دالة التحديث بحيث تمرر
	// إلى الأسفل إلى مزود السياق
    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

function Content() {
  return (
    <div>
      <ThemeTogglerButton />
    </div>
  );
}

ReactDOM.render(<App />, document.root);


  render() {
	// تمرر كامل الحالة إلى المزود

استهلاك سياقات متعددة

لإبقاء قدرة السياق على إعادة التصيير بشكل سريع، تحتاج React إلى جعل كل مستهلك سياق على شكل عقدة منفصل في الشجرة:

// سياق القالب، بشكل افتراضي قيمته light
const ThemeContext = React.createContext('light');

// سياق المستخدم قيد تسجيل الدخول
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;
	// مكون التطبيق الذي يزودنا بقيم مبدئية للسياق
    return (
      <ThemeContext.Provider value={theme}>
        <UserContext.Provider value={signedInUser}>
          <Layout />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

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

// قد يستهلك المكون العديد من السياقات
function Content() {
  return (
    <ThemeContext.Consumer>
      {theme => (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
}

إن كانت قيمة سياقين أو أكثر مستخدمة معًا، فقد ترغب بالنظر إلى إنشاء مكون خاصية التصيير الخاص بك والذي يزودك بكليهما معًا.

محاذير Caveats

بما أنّ السياق يستخدم هوية المرجع لتحديد وقت إعادة التصيير، فهنالك بعض الأشياء التي قد تُطلِق تصييرات غير مقصودة في المستهلكات consumers عندما يُعيد المُزوِّد provider الأب التصيير. على سبيل المثال ستُعيد الشيفرة التالية تصيير جميع المستهلكات في كل مرة يُعيد فيها المُزوّد التصيير، وذلك بسبب إنشاء كائن جديد دومًا للخاصيّة value:

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something'}}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

ولكي تلتف على هذا احتفظ بقيمة value في حالة الأب:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}

واجهة برمجة التطبيقات القديمة

ملاحظة: كانت تأتي React سابقًا مع واجهة برمجة تطبيقات (API) تجريبية للسياق. ستبقى هذه الواجهة مدعومة في جميع الإصدارات ‎16.x‎، ولكن يجب على التطبيقات التي تستخدمها أن تنتقل للإصدار الجديد. ستُزال هذه الواجهة القديمة في إصدار React المستقبلي الرئيسي. اقرأ توثيق السياق القديم من هنا.

انظر أيضًا

 مصادر