الفرق بين المراجعتين ل"React/refs and the dom"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM}}</noinclude>')
 
سطر 1: سطر 1:
 
<noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM}}</noinclude>
 
<noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM}}</noinclude>
 +
تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع render.
 +
 +
تكون الخاصيّات في تدفّق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المُكوِّن الأب مع مُكوِّناته الأبناء، ولتعديل الابن نُعيد تصييره باستخدام الخاصيّات الجديدة. على الرغم من ذلك هنالك حالات نحتاج فيها بشكلٍ إجباري إلى تعديل المُكوِّنات الأبناء خارج هذا التدفّق النموذجي. لتعديل المُكوِّن الابن يجب أن يكون نسخة (instance) من مُكوِّن React أو عنصر DOM. ولكلتا الحالتين تُعطينا React خطة للالتفاف حول هذا الموضوع.
 +
 +
== متى نستخدم المراجع (Refs) ==
 +
هنالك بعض الحالات المناسبة لاستخدام المراجع (refs) وهي:
 +
* إدارة التركيز على العناصر (focus)، واختيار النصوص، والتحكم بتشغيل الوسائط.
 +
* إطلاق التحريكات الإجباريّة.
 +
* التكامل مع مكتبات طرف ثالث تتعامل مع DOM.
 +
تجنّب استخدام المراجع لأي شيء يُمكِن فعله بشكلٍ إلزامي. فمثلًا بدلًا من تعريض التوابع open()‎ و close()‎ في مُكوِّن مربّع الحوار Dialog، مرِّر الخاصيّة isOpen له.
 +
 +
== لا تُفرِط في استخدام المراجع ==
 +
ربّما تكون رغبتك الأولى لاستخدام المراجع هي تحقيق كل ما تُريده في تطبيقك. إن كانت هذه حالتك فخُذ لحظة للتفكير حول المكان المُلائم لوضع الحالة في التسلسل الهرمي للمُكوِّنات. يتضح عادةً أنّ المكان المناسب لوضع الحالة هو في المستويات العليا من التسلسل الهرمي للمُكوِّنات. انظر إلى قسم [[React/lifting state up|رفع الحالات المشتركة للمستوى الأعلى]] للمزيد من المعلومات.
 +
 +
ملاحظة: حدّثنا الأمثلة التالية لكي تستخدم واجهة برمجة التطبيق React.createRef()‎ التي قُدِّمَت في إصدار React 16.3. إن كُنتَ تستخدم إصدار أقدم من React نُوصي باستخدام ردود نداء المراجع بدلًا من ذلك.
 +
 +
== إنشاء المراجع ==
 +
تُنشَأ المراجع باستخدام React.createRef()‎ وتُربَط إلى عناصر React عبر الخاصيّة ref. تُعيَّن المراجع إلى نسخة من الخاصيّة عند بناء المُكوِّنات لكي نرجع إليها عبر المُكوِّن:<syntaxhighlight lang="javascript">
 +
class MyComponent extends React.Component {
 +
  constructor(props) {
 +
    super(props);
 +
    this.myRef = React.createRef();
 +
  }
 +
  render() {
 +
    return <div ref={this.myRef} />;
 +
  }
 +
}
 +
 +
</syntaxhighlight>
 +
 +
== الوصول للمراجع ==
 +
عند تمرير المرجع إلى عنصر في التابع render، يُصبِح المرجع إلى العقدة قابلًا للوصول باستخدام الخاصّية current للمرجع:<syntaxhighlight lang="javascript">
 +
const node = this.myRef.current;
 +
</syntaxhighlight>تختلف قيمة المرجع بناءً على نوع العقدة:
 +
* عند استخدام الخاصيّة ref على عنصر HTML، تستقبل هذه الخاصيّة ref المُنشَأة في الدالة البانية باستخدام React.createRef()‎ عنصر DOM كخاصيّة حاليّة current.
 +
* عند استخدام الخاصيّة ref على مُكوِّن صنف مُخصَّص، يستقبل الكائن ref نسخة من المُكوِّن كخاصيّة حاليّة current.
 +
* لا يُمكنك استخدام الخاصيّة ref على المُكوِّنات المُعرَّفة كدوال لأنّها لا تملك نُسَخ (instances).
 +
يُوضِّح المثال التالي الفروقات.
 +
 +
=== إضافة مرجع إلى عنصر DOM ===
 +
تستخدم هذه الشيفرة الخاصيّة ref لتخزين مرجع إلى عقدة DOM:<syntaxhighlight lang="javascript">
 +
class CustomTextInput extends React.Component {
 +
  constructor(props) {
 +
    super(props);
 +
// إنشاء مرجع لتخزين عقدة DOM وهي textInput
 +
    this.textInput = React.createRef();
 +
    this.focusTextInput = this.focusTextInput.bind(this);
 +
  }
 +
 +
  focusTextInput() {
 +
// التركيز على الحقل النصي باستخدام DOM API
 +
// ملاحظة: نحن نصل إلى الخاصيّة current للحصول على عقدة DOM
 +
    this.textInput.current.focus();
 +
  }
 +
 +
  render() {
 +
// إخبار React أننا نريد ربط مرجع العنصر input
 +
// مع textInput التي أنشأناها في الدالة البانية
 +
    return (
 +
      <div>
 +
        <input
 +
          type="text"
 +
          ref={this.textInput} />
 +
 +
        <input
 +
          type="button"
 +
          value="ركز على الحقل النصي"
 +
          onClick={this.focusTextInput}
 +
        />
 +
      </div>
 +
    );
 +
  }
 +
}
 +
 +
</syntaxhighlight>ستُعيِّن React الخاصيّة current إلى عنصر DOM عندما وصل المُكوِّن (mount)، وتُعيِّنها إلى القيمة null عند فصل المُكوِّن (unmount). تحصل تحديثات ref قبل خُطافات دورة حياة المُكوِّن componentDidMount أو componentDidUpdate.
 +
 +
=== إضافة مرجع إلى مُكوِّن الصنف ===
 +
إن أردنا تغليف المُكوِّن CustomTextInput السّابق لمُحاكاة النقر عليها فورًا بعد الوصل (mounting)، فبإمكاننا استخدام المرجع ref للوصول إلى حقل الإدخال المُخصَّص واستدعاء تابعه focusTextInput بشكل يدوي:<syntaxhighlight lang="javascript">
 +
class AutoFocusTextInput extends React.Component {
 +
  constructor(props) {
 +
    super(props);
 +
    this.textInput = React.createRef();
 +
  }
 +
 +
  componentDidMount() {
 +
    this.textInput.current.focusTextInput();
 +
  }
 +
 +
  render() {
 +
    return (
 +
      <CustomTextInput ref={this.textInput} />
 +
    );
 +
  }
 +
}
 +
 +
</syntaxhighlight>لاحظ أنّ هذا يعمل فقط إن كان المُكوِّن CustomTextInput مُعرَّفًا كصنف:<syntaxhighlight lang="javascript">
 +
class CustomTextInput extends React.Component {
 +
  // ...
 +
}
 +
 +
</syntaxhighlight>
 +
 +
=== المراجع والمكونات الدالية ===
 +
لا يُمكنِك استخدام الخاصيّة ref على المُكوِّنات الداليّة لأنّها لا تمتلك نُسَخ:<syntaxhighlight lang="javascript">
 +
function MyFunctionalComponent() {
 +
  return <input />;
 +
}
 +
 +
class Parent extends React.Component {
 +
  constructor(props) {
 +
    super(props);
 +
    this.textInput = React.createRef();
 +
  }
 +
  render() {
 +
// لن يعمل هذا
 +
    return (
 +
      <MyFunctionalComponent ref={this.textInput} />
 +
    );
 +
  }
 +
}
 +
 +
</syntaxhighlight>

مراجعة 09:59، 3 أغسطس 2018

تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع render.

تكون الخاصيّات في تدفّق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المُكوِّن الأب مع مُكوِّناته الأبناء، ولتعديل الابن نُعيد تصييره باستخدام الخاصيّات الجديدة. على الرغم من ذلك هنالك حالات نحتاج فيها بشكلٍ إجباري إلى تعديل المُكوِّنات الأبناء خارج هذا التدفّق النموذجي. لتعديل المُكوِّن الابن يجب أن يكون نسخة (instance) من مُكوِّن React أو عنصر DOM. ولكلتا الحالتين تُعطينا React خطة للالتفاف حول هذا الموضوع.

متى نستخدم المراجع (Refs)

هنالك بعض الحالات المناسبة لاستخدام المراجع (refs) وهي:

  • إدارة التركيز على العناصر (focus)، واختيار النصوص، والتحكم بتشغيل الوسائط.
  • إطلاق التحريكات الإجباريّة.
  • التكامل مع مكتبات طرف ثالث تتعامل مع DOM.

تجنّب استخدام المراجع لأي شيء يُمكِن فعله بشكلٍ إلزامي. فمثلًا بدلًا من تعريض التوابع open()‎ و close()‎ في مُكوِّن مربّع الحوار Dialog، مرِّر الخاصيّة isOpen له.

لا تُفرِط في استخدام المراجع

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

ملاحظة: حدّثنا الأمثلة التالية لكي تستخدم واجهة برمجة التطبيق React.createRef()‎ التي قُدِّمَت في إصدار React 16.3. إن كُنتَ تستخدم إصدار أقدم من React نُوصي باستخدام ردود نداء المراجع بدلًا من ذلك.

إنشاء المراجع

تُنشَأ المراجع باستخدام React.createRef()‎ وتُربَط إلى عناصر React عبر الخاصيّة ref. تُعيَّن المراجع إلى نسخة من الخاصيّة عند بناء المُكوِّنات لكي نرجع إليها عبر المُكوِّن:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

الوصول للمراجع

عند تمرير المرجع إلى عنصر في التابع render، يُصبِح المرجع إلى العقدة قابلًا للوصول باستخدام الخاصّية current للمرجع:

const node = this.myRef.current;

تختلف قيمة المرجع بناءً على نوع العقدة:

  • عند استخدام الخاصيّة ref على عنصر HTML، تستقبل هذه الخاصيّة ref المُنشَأة في الدالة البانية باستخدام React.createRef()‎ عنصر DOM كخاصيّة حاليّة current.
  • عند استخدام الخاصيّة ref على مُكوِّن صنف مُخصَّص، يستقبل الكائن ref نسخة من المُكوِّن كخاصيّة حاليّة current.
  • لا يُمكنك استخدام الخاصيّة ref على المُكوِّنات المُعرَّفة كدوال لأنّها لا تملك نُسَخ (instances).

يُوضِّح المثال التالي الفروقات.

إضافة مرجع إلى عنصر DOM

تستخدم هذه الشيفرة الخاصيّة ref لتخزين مرجع إلى عقدة DOM:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
	// إنشاء مرجع لتخزين عقدة DOM وهي textInput
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
	// التركيز على الحقل النصي باستخدام DOM API
	// ملاحظة: نحن نصل إلى الخاصيّة current للحصول على عقدة DOM
    this.textInput.current.focus();
  }

  render() {
	// إخبار React أننا نريد ربط مرجع العنصر input
	// مع textInput التي أنشأناها في الدالة البانية
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />

        <input
          type="button"
          value="ركز على الحقل النصي"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

ستُعيِّن React الخاصيّة current إلى عنصر DOM عندما وصل المُكوِّن (mount)، وتُعيِّنها إلى القيمة null عند فصل المُكوِّن (unmount). تحصل تحديثات ref قبل خُطافات دورة حياة المُكوِّن componentDidMount أو componentDidUpdate.

إضافة مرجع إلى مُكوِّن الصنف

إن أردنا تغليف المُكوِّن CustomTextInput السّابق لمُحاكاة النقر عليها فورًا بعد الوصل (mounting)، فبإمكاننا استخدام المرجع ref للوصول إلى حقل الإدخال المُخصَّص واستدعاء تابعه focusTextInput بشكل يدوي:

class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  componentDidMount() {
    this.textInput.current.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}

لاحظ أنّ هذا يعمل فقط إن كان المُكوِّن CustomTextInput مُعرَّفًا كصنف:

class CustomTextInput extends React.Component {
  // ...
}

المراجع والمكونات الدالية

لا يُمكنِك استخدام الخاصيّة ref على المُكوِّنات الداليّة لأنّها لا تمتلك نُسَخ:

function MyFunctionalComponent() {
  return <input />;
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  render() {
	// لن يعمل هذا
    return (
      <MyFunctionalComponent ref={this.textInput} />
    );
  }
}