الفرق بين المراجعتين لصفحة: «React/refs and the dom»
Kinan-mawed (نقاش | مساهمات) لا ملخص تعديل |
Kinan-mawed (نقاش | مساهمات) لا ملخص تعديل |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM}}</noinclude> | <noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM}}</noinclude> | ||
تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع render. | تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع <code>render</code>. | ||
تكون الخاصيّات في تدفّق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المُكوِّن الأب مع مُكوِّناته الأبناء، ولتعديل الابن نُعيد تصييره باستخدام الخاصيّات الجديدة. على الرغم من ذلك هنالك حالات نحتاج فيها بشكلٍ إجباري إلى تعديل المُكوِّنات الأبناء خارج هذا التدفّق النموذجي. لتعديل المُكوِّن الابن يجب أن يكون نسخة (instance) من مُكوِّن React أو عنصر DOM. ولكلتا الحالتين تُعطينا React خطة للالتفاف حول هذا الموضوع. | تكون الخاصيّات في تدفّق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المُكوِّن الأب مع مُكوِّناته الأبناء، ولتعديل الابن نُعيد تصييره باستخدام الخاصيّات الجديدة. على الرغم من ذلك هنالك حالات نحتاج فيها بشكلٍ إجباري إلى تعديل المُكوِّنات الأبناء خارج هذا التدفّق النموذجي. لتعديل المُكوِّن الابن يجب أن يكون نسخة (instance) من مُكوِّن React أو عنصر DOM. ولكلتا الحالتين تُعطينا React خطة للالتفاف حول هذا الموضوع. | ||
== متى نستخدم المراجع (Refs) == | == متى نستخدم المراجع (Refs) == | ||
هنالك بعض الحالات المناسبة لاستخدام المراجع (refs) وهي: | هنالك بعض الحالات المناسبة لاستخدام المراجع (<code>refs</code>) وهي: | ||
* إدارة التركيز على العناصر (focus)، واختيار النصوص، والتحكم بتشغيل الوسائط. | * إدارة التركيز على العناصر (focus)، واختيار النصوص، والتحكم بتشغيل الوسائط. | ||
* إطلاق التحريكات الإجباريّة. | * إطلاق التحريكات الإجباريّة. | ||
* التكامل مع مكتبات طرف ثالث تتعامل مع DOM. | * التكامل مع مكتبات طرف ثالث تتعامل مع DOM. | ||
تجنّب استخدام المراجع لأي شيء يُمكِن فعله بشكلٍ إلزامي. فمثلًا بدلًا من تعريض التوابع open() و close() في مُكوِّن مربّع الحوار | تجنّب استخدام المراجع لأي شيء يُمكِن فعله بشكلٍ إلزامي. فمثلًا بدلًا من تعريض التوابع <code>open()</code> و <code>close()</code> في مُكوِّن مربّع الحوار <code>Dialog</code>، مرِّر الخاصيّة <code>isOpen</code> له. | ||
== لا تُفرِط في استخدام المراجع == | == لا تُفرِط في استخدام المراجع == | ||
ربّما تكون رغبتك الأولى لاستخدام المراجع هي تحقيق كل ما تُريده في تطبيقك. إن كانت هذه حالتك فخُذ لحظة للتفكير حول المكان المُلائم لوضع الحالة في التسلسل الهرمي للمُكوِّنات. يتضح عادةً أنّ المكان المناسب لوضع الحالة هو في المستويات العليا من التسلسل الهرمي للمُكوِّنات. انظر إلى قسم [[React/lifting state up|رفع الحالات المشتركة للمستوى الأعلى]] للمزيد من المعلومات. | ربّما تكون رغبتك الأولى لاستخدام المراجع هي تحقيق كل ما تُريده في تطبيقك. إن كانت هذه حالتك فخُذ لحظة للتفكير حول المكان المُلائم لوضع الحالة في التسلسل الهرمي للمُكوِّنات. يتضح عادةً أنّ المكان المناسب لوضع الحالة هو في المستويات العليا من التسلسل الهرمي للمُكوِّنات. انظر إلى قسم [[React/lifting state up|رفع الحالات المشتركة للمستوى الأعلى]] للمزيد من المعلومات. | ||
ملاحظة: حدّثنا الأمثلة التالية لكي تستخدم واجهة برمجة التطبيق React.createRef() التي قُدِّمَت في إصدار React 16.3. إن كُنتَ تستخدم إصدار أقدم من React نُوصي باستخدام ردود نداء المراجع بدلًا من ذلك. | '''ملاحظة:''' حدّثنا الأمثلة التالية لكي تستخدم واجهة برمجة التطبيق <code>React.createRef()</code> التي قُدِّمَت في إصدار React 16.3. إن كُنتَ تستخدم إصدار أقدم من React نُوصي باستخدام ردود نداء المراجع بدلًا من ذلك. | ||
== إنشاء المراجع == | == إنشاء المراجع == | ||
تُنشَأ المراجع باستخدام React.createRef() وتُربَط إلى عناصر React عبر الخاصيّة ref. تُعيَّن المراجع إلى نسخة من الخاصيّة عند بناء المُكوِّنات لكي نرجع إليها عبر المُكوِّن:<syntaxhighlight lang="javascript"> | تُنشَأ المراجع باستخدام <code>React.createRef()</code> وتُربَط إلى عناصر React عبر الخاصيّة <code>ref</code>. تُعيَّن المراجع إلى نسخة من الخاصيّة عند بناء المُكوِّنات لكي نرجع إليها عبر المُكوِّن:<syntaxhighlight lang="javascript"> | ||
class MyComponent extends React.Component { | class MyComponent extends React.Component { | ||
constructor(props) { | constructor(props) { | ||
سطر 31: | سطر 31: | ||
== الوصول للمراجع == | == الوصول للمراجع == | ||
عند تمرير المرجع إلى عنصر في التابع | عند تمرير المرجع إلى عنصر في التابع <code>render</code>، يُصبِح المرجع إلى العقدة قابلًا للوصول باستخدام الخاصّية <code>current</code> للمرجع:<syntaxhighlight lang="javascript"> | ||
const node = this.myRef.current; | const node = this.myRef.current; | ||
</syntaxhighlight>تختلف قيمة المرجع بناءً على نوع العقدة: | </syntaxhighlight>تختلف قيمة المرجع بناءً على نوع العقدة: | ||
* عند استخدام الخاصيّة ref على عنصر HTML، تستقبل هذه الخاصيّة ref المُنشَأة في الدالة البانية باستخدام React.createRef() عنصر DOM كخاصيّة حاليّة current. | * عند استخدام الخاصيّة <code>ref</code> على عنصر HTML، تستقبل هذه الخاصيّة <code>ref</code> المُنشَأة في الدالة البانية باستخدام <code>React.createRef()</code> عنصر DOM كخاصيّة حاليّة <code>current</code>. | ||
* عند استخدام الخاصيّة ref على مُكوِّن صنف مُخصَّص، يستقبل الكائن ref نسخة من المُكوِّن كخاصيّة حاليّة current. | * عند استخدام الخاصيّة <code>ref</code> على مُكوِّن صنف مُخصَّص، يستقبل الكائن <code>ref</code> نسخة من المُكوِّن كخاصيّة حاليّة <code>current</code>. | ||
* لا يُمكنك استخدام الخاصيّة ref على المُكوِّنات المُعرَّفة كدوال لأنّها لا تملك نُسَخ (instances). | * لا يُمكنك استخدام الخاصيّة <code>ref</code> على المُكوِّنات المُعرَّفة كدوال لأنّها لا تملك نُسَخ (instances). | ||
يُوضِّح المثال التالي الفروقات. | يُوضِّح المثال التالي الفروقات. | ||
=== إضافة مرجع إلى عنصر DOM === | === إضافة مرجع إلى عنصر DOM === | ||
تستخدم هذه الشيفرة الخاصيّة ref لتخزين مرجع إلى عقدة DOM:<syntaxhighlight lang="javascript"> | تستخدم هذه الشيفرة الخاصيّة <code>ref</code> لتخزين مرجع إلى عقدة DOM:<syntaxhighlight lang="javascript"> | ||
class CustomTextInput extends React.Component { | class CustomTextInput extends React.Component { | ||
constructor(props) { | constructor(props) { | ||
سطر 74: | سطر 74: | ||
} | } | ||
</syntaxhighlight>ستُعيِّن React الخاصيّة current إلى عنصر DOM عندما وصل المُكوِّن (mount)، وتُعيِّنها إلى القيمة null عند فصل المُكوِّن (unmount). تحصل تحديثات ref قبل خُطافات دورة حياة المُكوِّن componentDidMount أو componentDidUpdate. | </syntaxhighlight>ستُعيِّن React الخاصيّة <code>current</code> إلى عنصر DOM عندما وصل المُكوِّن (mount)، وتُعيِّنها إلى القيمة <code>null</code> عند فصل المُكوِّن (unmount). تحصل تحديثات <code>ref</code> قبل خُطافات دورة حياة المُكوِّن <code>componentDidMount</code> أو <code>componentDidUpdate</code>. | ||
=== إضافة مرجع إلى مُكوِّن الصنف === | === إضافة مرجع إلى مُكوِّن الصنف === |
مراجعة 10:03، 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} />
);
}
}
ينبغي تحويل المُكوِّن إلى صنف أن أردت إضافة مرجع له، تمامًا كما تفعل عندما تحتاج توابع دورة الحياة أو الحالة. على أيّة حال تستطيع استخدام الخاصيّة ref بداخل المُكوِّن المُعرَّف كدالة طالما تُشير إلى عنصر DOM أو مُكوِّن مُعرَّف كصنف:
function CustomTextInput(props) {
// يجب تعريف textInput هنا لكي يستطيع المرجع الرجوع إليها
let textInput = React.createRef();
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="ركز على الحقل النصي"
onClick={handleClick}
/>
</div>
);
}
تعريض مراجع DOM للمكون الأب
قد ترغب في بعض الحالات النادرة الوصول إلى عقدة DOM للمُكوِّن الابن من خلال المُكوِّن الأب. لا يُفضَّل فعل ذلك بشكل عام لأنّه قد يخرق تغليف المُكوِّن، ولكن قد يكون أحيانًا مفيدًا لإطلاق حدث التركيز أو قياس حجم أو موضع عقدة DOM للمُكوِّن الابن.
وبينما تستطيع إضافة مرجع إلى المُكوِّن الابن فليس هذا الحل الأمثل، حيث ستحصل فقط على نسخة عن المُكوِّن بدلًا من عقدة DOM. ولا يعمل هذا أيضًا على المُكوِّنات الدالية.
إن كُنتَ تستخدم إصدار React 16.3 أو أحدث، فنوصي باستخدام تمرير المراجع لأجل هذه الحالات. حيث يُتيح ذلك للمُكوِّنات أن تُعرِّض أي مرجع للمُكوِّن الابن كمرجع خاص بها. ستجد مثالًا مُفصّلًا حول كيفيّة تعريض عقدة DOM للابن إلى المُكوِّن الأب في صفحة تمرير المراجع من هذا التوثيق.
إن كُنتَ تستخدم إصدار React 16.2 أو أقدم، أو احتجتَ مرونة أكبر من تلك التي يُعطيك إيّاها تمرير المراجع، فتستطيع استخدام هذه المقاربة المختلفة لتمرير مرجع كخاصيّة ذات اسم مُختلِف.
ننصح بقدر الإمكان تجنّب تعريض عُقَد DOM، ولكن قد يكون أحيانًا هذا حلًّا جيّدًا للالتفاف حول هذه المشكلة. لاحظ حاجة هذه المقاربة إلى إضافة بعض الشيفرة إلى المُكوِّن الابن. إن لم يكن لديك أي تحكّم بالمُكوِّن الابن فخيارك الأخير هو استخدام findDOMNode()، ولكن لا نُوصي بهذا.
ردود نداء المراجع
تدعم React أيضًا طريقة أخرى لتعيين المراجع تُدعى ردود نداء المراجع (callback refs)، والتي تُعطي درجة أكبر من التحكم عند تعيين وإزالة تعيين المراجع.
بدلًا من تمرير الخاصيّة ref المُنشَأة من قبل التابع createRef()، مرِّر دالة. تستقبل هذه الدالة نسخة من مُكوِّن React أو عنصر DOM كوسائط لها، والتي يُمكِن تخزينها والوصول إليها من مكان آخر.
يعتمد المثال التالي نمطًا شائعًا: وهو استخدام رد نداء ref لتخزين مرجع إلى عقدة DOM في نسخة من الخاصيّة:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => {
this.textInput = element;
};
this.focusTextInput = () => {
// التركيز على الحقل النصي باستخدام DOM API
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// التركيز التلقائي على الحقل النصي عند وصل المُكوِّن (mount)
this.focusTextInput();
}
render() {
// استخدم رد نداء المرجع لتخزين مرجع إلى عنصر DOM للحقل النصي
// في نسخة من الحقل (مثل this.textInput)
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="التركيز على الحقل النصي"
onClick={this.focusTextInput}
/>
</div>
);
}
}
ستستدعي React رد نداء ref عن طريق عنصر DOM عند وصل المُكوِّن (mount)، وتستدعيه مع القيمة null عند فصل المُكوِّن (unmount). نضمن أن تكون قيمة المراجع مُحدَّثة قبل إطلاق توابع المُكوِّن componentDidMount أو componentDidUpdate. تستطيع تمرير ردود نداء المراجع بين المُكوِّنات كما تفعل بين كائنات المراجع التي يُنشِئها React.createRef():
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
في المثال السّابق يُمرِّر المُكوِّن Parent رد نداء المرجع من خلال الخاصيّة inputRef إلى المُكوِّن CustomTextInput والذي يُمرِّر نفس الدالة كخاصيّة ref إلى العنصر <input>، وكنتيجة لذلك تُعيَّن this.inputElement في المُكوِّن Parent إلى عقدة DOM المُوافِقة للعنصر <input> في المُكوِّن CustomTextInput.
واجهة برمجة التطبيق API القديمة: مراجع السلاسل النصية
إن تعاملتَ مع React سابقًا فقد تكون متآلفًا مع واجهة برمجة التطبيق (API) القديمة حيث كانت الخاصيّة ref عبارة عن سلسلة نصيّة، مثل textInput، ونصل إلى عقدة DOM عبر this.refs.textInput. لا ننصح بفعل ذلك لأنّ مراجع السلاسل النصيّة لديها بعض المشاكل، وأصبحت مُهمَلة في React، ومن المحتمل أنّها ستُزال في الإصدارات القادمة.
ملاحظة: إن كنتَ تستخدم this.refs.textInput حاليًّا للوصول إلى المراجع، فيُفضَّل أن تستخدم إمّا نمط ردود النداء أو createRef API بدلًا من ذلك.
محاذير استخدام ردود نداء المراجع
إن كان رد نداء المرجع مُعرَّفًا كدالة سطريّة (inline)، فسيُستدعى مرتين خلال التحديثات، أول مرة مع القيمة null ومرة أخرى مع عنصر DOM، وهذا بسبب إنشاء نسخة جديدة من الدالة مع كل تصيير، لذا تحتاج React إلى مسح المرجع القديم وإعداد واحد جديد. بإمكانك تجنّب ذلك عن طريق تعريف رد نداء المرجع كتابع مربوط في الصنف، ولكن لاحظ أنّ هذا غير هام في معظم الحالات.