الفرق بين المراجعتين ل"React/refs and the dom"
Kinan-mawed (نقاش | مساهمات) |
(تحديث) |
||
(5 مراجعات متوسطة بواسطة 3 مستخدمين غير معروضة) | |||
سطر 1: | سطر 1: | ||
− | <noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM}}</noinclude> | + | <noinclude>{{DISPLAYTITLE:استخدام المراجع مع DOM في React}}</noinclude> |
تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع <code>render</code>. | تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع <code>render</code>. | ||
− | تكون الخاصيّات في تدفّق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المُكوِّن الأب مع مُكوِّناته الأبناء، ولتعديل الابن نُعيد تصييره باستخدام الخاصيّات الجديدة. على الرغم من ذلك هنالك حالات نحتاج فيها بشكلٍ إجباري إلى تعديل المُكوِّنات الأبناء خارج هذا التدفّق النموذجي. لتعديل المُكوِّن الابن يجب أن يكون نسخة (instance) من مُكوِّن React أو عنصر DOM. ولكلتا الحالتين تُعطينا React خطة للالتفاف حول هذا الموضوع. | + | تكون [[React/components and props|الخاصيّات]] في تدفّق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المُكوِّن الأب مع مُكوِّناته الأبناء، ولتعديل الابن نُعيد تصييره باستخدام الخاصيّات الجديدة. على الرغم من ذلك هنالك حالات نحتاج فيها بشكلٍ إجباري إلى تعديل المُكوِّنات الأبناء خارج هذا التدفّق النموذجي. لتعديل المُكوِّن الابن يجب أن يكون نسخة (instance) من مُكوِّن React أو عنصر DOM. ولكلتا الحالتين تُعطينا React خطة للالتفاف حول هذا الموضوع. |
== متى نستخدم المراجع (Refs) == | == متى نستخدم المراجع (Refs) == | ||
سطر 14: | سطر 14: | ||
ربّما تكون رغبتك الأولى لاستخدام المراجع هي تحقيق كل ما تُريده في تطبيقك. إن كانت هذه حالتك فخُذ لحظة للتفكير حول المكان المُلائم لوضع الحالة في التسلسل الهرمي للمُكوِّنات. يتضح عادةً أنّ المكان المناسب لوضع الحالة هو في المستويات العليا من التسلسل الهرمي للمُكوِّنات. انظر إلى قسم [[React/lifting state up|رفع الحالات المشتركة للمستوى الأعلى]] للمزيد من المعلومات. | ربّما تكون رغبتك الأولى لاستخدام المراجع هي تحقيق كل ما تُريده في تطبيقك. إن كانت هذه حالتك فخُذ لحظة للتفكير حول المكان المُلائم لوضع الحالة في التسلسل الهرمي للمُكوِّنات. يتضح عادةً أنّ المكان المناسب لوضع الحالة هو في المستويات العليا من التسلسل الهرمي للمُكوِّنات. انظر إلى قسم [[React/lifting state up|رفع الحالات المشتركة للمستوى الأعلى]] للمزيد من المعلومات. | ||
− | '''ملاحظة:''' حدّثنا الأمثلة التالية لكي تستخدم واجهة برمجة التطبيق <code>React.createRef()</code> التي قُدِّمَت في إصدار React 16.3. إن كُنتَ تستخدم إصدار أقدم من React نُوصي باستخدام ردود نداء المراجع بدلًا من ذلك. | + | '''ملاحظة:''' حدّثنا الأمثلة التالية لكي تستخدم واجهة برمجة التطبيق <code>React.createRef()</code> التي قُدِّمَت في إصدار React 16.3. إن كُنتَ تستخدم إصدار أقدم من React نُوصي باستخدام [[React/refs and the dom#.D8.B1.D8.AF.D9.88.D8.AF .D9.86.D8.AF.D8.A7.D8.A1 .D8.A7.D9.84.D9.85.D8.B1.D8.A7.D8.AC.D8.B9|ردود نداء المراجع]] بدلًا من ذلك. |
== إنشاء المراجع == | == إنشاء المراجع == | ||
سطر 77: | سطر 77: | ||
=== إضافة مرجع إلى مُكوِّن الصنف === | === إضافة مرجع إلى مُكوِّن الصنف === | ||
− | إن أردنا تغليف المُكوِّن CustomTextInput السّابق لمُحاكاة النقر عليها فورًا بعد الوصل (mounting)، فبإمكاننا استخدام المرجع ref للوصول إلى حقل الإدخال المُخصَّص واستدعاء تابعه focusTextInput بشكل يدوي:<syntaxhighlight lang="javascript"> | + | إن أردنا تغليف المُكوِّن <code>CustomTextInput</code> السّابق لمُحاكاة النقر عليها فورًا بعد الوصل (mounting)، فبإمكاننا استخدام المرجع <code>ref</code> للوصول إلى حقل الإدخال المُخصَّص واستدعاء تابعه <code>focusTextInput</code> بشكل يدوي:<syntaxhighlight lang="javascript"> |
class AutoFocusTextInput extends React.Component { | class AutoFocusTextInput extends React.Component { | ||
constructor(props) { | constructor(props) { | ||
سطر 95: | سطر 95: | ||
} | } | ||
− | </syntaxhighlight>لاحظ أنّ هذا يعمل فقط إن كان المُكوِّن CustomTextInput مُعرَّفًا كصنف:<syntaxhighlight lang="javascript"> | + | </syntaxhighlight>لاحظ أنّ هذا يعمل فقط إن كان المُكوِّن <code>CustomTextInput</code> مُعرَّفًا كصنف:<syntaxhighlight lang="javascript"> |
class CustomTextInput extends React.Component { | class CustomTextInput extends React.Component { | ||
// ... | // ... | ||
سطر 103: | سطر 103: | ||
=== المراجع والمكونات الدالية === | === المراجع والمكونات الدالية === | ||
− | لا يُمكنِك استخدام الخاصيّة ref على المُكوِّنات الداليّة لأنّها لا تمتلك نُسَخ:<syntaxhighlight lang="javascript"> | + | لا يُمكنِك استخدام الخاصيّة <code>ref</code> على المُكوِّنات الداليّة لأنّها لا تمتلك نُسَخ:<syntaxhighlight lang="javascript"> |
function MyFunctionalComponent() { | function MyFunctionalComponent() { | ||
return <input />; | return <input />; | ||
سطر 121: | سطر 121: | ||
} | } | ||
− | </syntaxhighlight> | + | </syntaxhighlight>إذا أردت السماح للناس بتمرير مرجع لمكون دالي، فعليك استخدام <code>forwardRef</code> (ربما مع <code>useImperativeHandle</code>)، أو يمكنك تحويل المكون إلى صنف. |
− | على أيّة حال تستطيع استخدام الخاصيّة ref بداخل المُكوِّن المُعرَّف كدالة طالما تُشير إلى عنصر DOM أو مُكوِّن مُعرَّف كصنف:<syntaxhighlight lang="javascript"> | + | على أيّة حال تستطيع استخدام الخاصيّة <code>ref</code> بداخل المُكوِّن المُعرَّف كدالة طالما تُشير إلى عنصر DOM أو مُكوِّن مُعرَّف كصنف:<syntaxhighlight lang="javascript"> |
function CustomTextInput(props) { | function CustomTextInput(props) { | ||
// يجب تعريف textInput هنا لكي يستطيع المرجع الرجوع إليها | // يجب تعريف textInput هنا لكي يستطيع المرجع الرجوع إليها | ||
− | + | const textInput = useRef(null); | |
− | + | ||
function handleClick() { | function handleClick() { | ||
textInput.current.focus(); | textInput.current.focus(); | ||
سطر 137: | سطر 137: | ||
type="text" | type="text" | ||
ref={textInput} /> | ref={textInput} /> | ||
− | |||
<input | <input | ||
type="button" | type="button" | ||
سطر 152: | سطر 151: | ||
قد ترغب في بعض الحالات النادرة الوصول إلى عقدة DOM للمُكوِّن الابن من خلال المُكوِّن الأب. لا يُفضَّل فعل ذلك بشكل عام لأنّه قد يخرق تغليف المُكوِّن، ولكن قد يكون أحيانًا مفيدًا لإطلاق حدث التركيز أو قياس حجم أو موضع عقدة DOM للمُكوِّن الابن. | قد ترغب في بعض الحالات النادرة الوصول إلى عقدة DOM للمُكوِّن الابن من خلال المُكوِّن الأب. لا يُفضَّل فعل ذلك بشكل عام لأنّه قد يخرق تغليف المُكوِّن، ولكن قد يكون أحيانًا مفيدًا لإطلاق حدث التركيز أو قياس حجم أو موضع عقدة DOM للمُكوِّن الابن. | ||
− | وبينما تستطيع إضافة مرجع إلى المُكوِّن الابن فليس هذا الحل الأمثل، حيث ستحصل فقط على نسخة عن المُكوِّن بدلًا من عقدة DOM. ولا يعمل هذا أيضًا على المُكوِّنات الدالية. | + | وبينما تستطيع [[React/refs and the dom#.D8.A5.D8.B6.D8.A7.D9.81.D8.A9 .D9.85.D8.B1.D8.AC.D8.B9 .D8.A5.D9.84.D9.89 .D9.85.D9.8F.D9.83.D9.88.D9.90.D9.91.D9.86 .D8.A7.D9.84.D8.B5.D9.86.D9.81|إضافة مرجع إلى المُكوِّن الابن]] فليس هذا الحل الأمثل، حيث ستحصل فقط على نسخة عن المُكوِّن بدلًا من عقدة DOM. ولا يعمل هذا أيضًا على المُكوِّنات الدالية. |
− | إن كُنتَ تستخدم إصدار React 16.3 أو أحدث، فنوصي باستخدام تمرير المراجع لأجل هذه الحالات. حيث يُتيح ذلك للمُكوِّنات أن تُعرِّض أي مرجع للمُكوِّن الابن كمرجع خاص بها. ستجد مثالًا مُفصّلًا حول كيفيّة تعريض عقدة DOM للابن إلى المُكوِّن الأب في صفحة تمرير المراجع من هذا التوثيق. | + | إن كُنتَ تستخدم إصدار React 16.3 أو أحدث، فنوصي باستخدام [[React/forwarding refs|تمرير المراجع]] لأجل هذه الحالات. حيث يُتيح ذلك للمُكوِّنات أن تُعرِّض أي مرجع للمُكوِّن الابن كمرجع خاص بها. ستجد مثالًا مُفصّلًا حول كيفيّة تعريض عقدة DOM للابن إلى المُكوِّن الأب في [[React/forwarding refs|صفحة تمرير المراجع]] من هذا التوثيق. |
− | إن كُنتَ تستخدم إصدار React 16.2 أو أقدم، أو احتجتَ مرونة أكبر من تلك التي يُعطيك إيّاها تمرير المراجع، فتستطيع استخدام هذه المقاربة المختلفة لتمرير مرجع كخاصيّة ذات اسم مُختلِف. | + | إن كُنتَ تستخدم إصدار React 16.2 أو أقدم، أو احتجتَ مرونة أكبر من تلك التي يُعطيك إيّاها تمرير المراجع، فتستطيع استخدام [https://gist.github.com/gaearon/1a018a023347fe1c2476073330cc5509 هذه المقاربة المختلفة] لتمرير مرجع كخاصيّة ذات اسم مُختلِف. |
− | ننصح بقدر الإمكان تجنّب تعريض عُقَد DOM، ولكن قد يكون أحيانًا هذا حلًّا جيّدًا للالتفاف حول هذه المشكلة. لاحظ حاجة هذه المقاربة إلى إضافة بعض الشيفرة إلى المُكوِّن الابن. إن لم يكن لديك أي تحكّم بالمُكوِّن الابن فخيارك الأخير هو استخدام findDOMNode() | + | ننصح بقدر الإمكان تجنّب تعريض عُقَد DOM، ولكن قد يكون أحيانًا هذا حلًّا جيّدًا للالتفاف حول هذه المشكلة. لاحظ حاجة هذه المقاربة إلى إضافة بعض الشيفرة إلى المُكوِّن الابن. إن لم يكن لديك أي تحكّم بالمُكوِّن الابن فخيارك الأخير هو استخدام <code>[[React/react dom|findDOMNode()]]</code>، ولكن لا نُوصي بهذا كما أنّها مُتجاوزة في [[React/strict mode|الوضع<code>StrictMode</code>]]. |
== ردود نداء المراجع == | == ردود نداء المراجع == | ||
تدعم React أيضًا طريقة أخرى لتعيين المراجع تُدعى ردود نداء المراجع (callback refs)، والتي تُعطي درجة أكبر من التحكم عند تعيين وإزالة تعيين المراجع. | تدعم React أيضًا طريقة أخرى لتعيين المراجع تُدعى ردود نداء المراجع (callback refs)، والتي تُعطي درجة أكبر من التحكم عند تعيين وإزالة تعيين المراجع. | ||
− | بدلًا من تمرير الخاصيّة ref المُنشَأة من قبل التابع createRef()، مرِّر دالة. تستقبل هذه الدالة نسخة من مُكوِّن React أو عنصر DOM كوسائط لها، والتي يُمكِن تخزينها والوصول إليها من مكان آخر. | + | بدلًا من تمرير الخاصيّة <code>ref</code> المُنشَأة من قبل التابع <code>createRef()</code>، مرِّر دالة. تستقبل هذه الدالة نسخة من مُكوِّن React أو عنصر 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) { | ||
سطر 206: | سطر 205: | ||
} | } | ||
− | </syntaxhighlight>ستستدعي React رد نداء ref عن طريق عنصر DOM عند وصل المُكوِّن (mount)، وتستدعيه مع القيمة null عند فصل المُكوِّن (unmount). نضمن أن تكون قيمة المراجع مُحدَّثة قبل إطلاق توابع المُكوِّن componentDidMount أو componentDidUpdate. | + | </syntaxhighlight>ستستدعي React رد نداء <code>ref</code> عن طريق عنصر DOM عند وصل المُكوِّن (mount)، وتستدعيه مع القيمة <code>null</code> عند فصل المُكوِّن (unmount). نضمن أن تكون قيمة المراجع مُحدَّثة قبل إطلاق توابع المُكوِّن <code>componentDidMount</code> أو <code>componentDidUpdate</code>. |
− | تستطيع تمرير ردود نداء المراجع بين المُكوِّنات كما تفعل بين كائنات المراجع التي يُنشِئها React.createRef():<syntaxhighlight lang="javascript"> | + | تستطيع تمرير ردود نداء المراجع بين المُكوِّنات كما تفعل بين كائنات المراجع التي يُنشِئها <code>React.createRef()</code>:<syntaxhighlight lang="javascript"> |
function CustomTextInput(props) { | function CustomTextInput(props) { | ||
return ( | return ( | ||
سطر 226: | سطر 225: | ||
} | } | ||
} | } | ||
− | + | </syntaxhighlight>في المثال السّابق يُمرِّر المُكوِّن <code>Parent</code> رد نداء المرجع من خلال الخاصيّة <code>inputRef</code> إلى المُكوِّن <code>CustomTextInput</code> والذي يُمرِّر نفس الدالة كخاصيّة <code>ref</code> إلى العنصر <code><input></code>، وكنتيجة لذلك تُعيَّن <code>this.inputElement</code> في المُكوِّن <code>Parent</code> إلى عقدة DOM المُوافِقة للعنصر <code><input></code> في المُكوِّن <code>CustomTextInput</code>. | |
− | </syntaxhighlight>في المثال السّابق يُمرِّر المُكوِّن Parent رد نداء المرجع من خلال الخاصيّة inputRef إلى المُكوِّن CustomTextInput والذي يُمرِّر نفس الدالة كخاصيّة ref إلى العنصر <input>، وكنتيجة لذلك تُعيَّن this.inputElement في المُكوِّن Parent إلى عقدة DOM المُوافِقة للعنصر <input> في المُكوِّن CustomTextInput. | ||
== واجهة برمجة التطبيق API القديمة: مراجع السلاسل النصية == | == واجهة برمجة التطبيق API القديمة: مراجع السلاسل النصية == | ||
− | إن تعاملتَ مع React سابقًا فقد تكون متآلفًا مع واجهة برمجة التطبيق (API) القديمة حيث كانت الخاصيّة ref عبارة عن سلسلة نصيّة، مثل | + | إن تعاملتَ مع React سابقًا فقد تكون متآلفًا مع واجهة برمجة التطبيق (API) القديمة حيث كانت الخاصيّة <code>ref</code> عبارة عن سلسلة نصيّة، مثل <code>textInput</code>، ونصل إلى عقدة DOM عبر <code>this.refs.textInput</code>. لا ننصح بفعل ذلك لأنّ مراجع السلاسل النصيّة لديها [https://github.com/facebook/react/pull/8333#issuecomment-271648615 بعض المشاكل]، وأصبحت مُهمَلة في React، ومن المحتمل أنّها ستُزال في الإصدارات القادمة. |
− | ملاحظة: إن كنتَ تستخدم this.refs.textInput حاليًّا للوصول إلى المراجع، فيُفضَّل أن تستخدم إمّا نمط ردود النداء أو createRef API بدلًا من ذلك. | + | '''ملاحظة:''' إن كنتَ تستخدم <code>this.refs.textInput</code> حاليًّا للوصول إلى المراجع، فيُفضَّل أن تستخدم إمّا [[React/refs and the dom#.D8.B1.D8.AF.D9.88.D8.AF .D9.86.D8.AF.D8.A7.D8.A1 .D8.A7.D9.84.D9.85.D8.B1.D8.A7.D8.AC.D8.B9|نمط ردود النداء]] أو [[React/refs and the dom#.D8.A5.D9.86.D8.B4.D8.A7.D8.A1 .D8.A7.D9.84.D9.85.D8.B1.D8.A7.D8.AC.D8.B9|createRef API]] بدلًا من ذلك. |
== محاذير استخدام ردود نداء المراجع == | == محاذير استخدام ردود نداء المراجع == | ||
− | إن كان رد نداء المرجع مُعرَّفًا كدالة سطريّة (inline)، فسيُستدعى مرتين خلال التحديثات، أول مرة مع القيمة null ومرة أخرى مع عنصر DOM، وهذا بسبب إنشاء نسخة جديدة من الدالة مع كل تصيير، لذا تحتاج React إلى مسح المرجع القديم وإعداد واحد جديد. بإمكانك تجنّب ذلك عن طريق تعريف رد نداء المرجع كتابع مربوط في الصنف، ولكن لاحظ أنّ هذا غير هام في معظم الحالات. | + | إن كان رد نداء المرجع مُعرَّفًا كدالة سطريّة (inline)، فسيُستدعى مرتين خلال التحديثات، أول مرة مع القيمة <code>null</code> ومرة أخرى مع عنصر DOM، وهذا بسبب إنشاء نسخة جديدة من الدالة مع كل تصيير، لذا تحتاج React إلى مسح المرجع القديم وإعداد واحد جديد. بإمكانك تجنّب ذلك عن طريق تعريف رد نداء المرجع كتابع مربوط في الصنف، ولكن لاحظ أنّ هذا غير هام في معظم الحالات. |
+ | == انظر أيضًا == | ||
+ | * [[React/jsx in depth|شرح JSX بالتفصيل]] | ||
+ | * [[React/static type checking|التحقق من الأنواع الثابتة]] | ||
+ | * [[React/typechecking with proptypes|التحقق من الأنواع باستخدام PropTypes]] | ||
+ | * [[React/uncontrolled components|المكونات غير المضبوطة]] | ||
+ | * [[React/optimizing performance|تحسين الأداء]] | ||
+ | * [[React/react without es6|React بدون ES6]] | ||
+ | * [[React/react without jsx|React بدون JSX]] | ||
+ | * [[React/reconciliation|المطابقة (Reconciliation)]] | ||
+ | * [[React/context|استخدام السياق (Context) في React]] | ||
+ | * [[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/refs-and-the-dom.html صفحة استخدام المراجع مع DOM في توثيق React الرسمي]. | ||
+ | [[تصنيف:React]] | ||
+ | [[تصنيف:React Advanced Guides]] |
المراجعة الحالية بتاريخ 10:25، 4 نوفمبر 2020
تُزوّدنا المراجع بطريقة للوصول إلى عقد 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} />
);
}
}
إذا أردت السماح للناس بتمرير مرجع لمكون دالي، فعليك استخدام forwardRef
(ربما مع useImperativeHandle
)، أو يمكنك تحويل المكون إلى صنف.
على أيّة حال تستطيع استخدام الخاصيّة ref
بداخل المُكوِّن المُعرَّف كدالة طالما تُشير إلى عنصر DOM أو مُكوِّن مُعرَّف كصنف:
function CustomTextInput(props) {
// يجب تعريف textInput هنا لكي يستطيع المرجع الرجوع إليها
const textInput = useRef(null);
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()
، ولكن لا نُوصي بهذا كما أنّها مُتجاوزة في الوضعStrictMode
.
ردود نداء المراجع
تدعم 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 إلى مسح المرجع القديم وإعداد واحد جديد. بإمكانك تجنّب ذلك عن طريق تعريف رد نداء المرجع كتابع مربوط في الصنف، ولكن لاحظ أنّ هذا غير هام في معظم الحالات.
انظر أيضًا
- شرح JSX بالتفصيل
- التحقق من الأنواع الثابتة
- التحقق من الأنواع باستخدام PropTypes
- المكونات غير المضبوطة
- تحسين الأداء
- React بدون ES6
- React بدون JSX
- المطابقة (Reconciliation)
- استخدام السياق (Context) في React
- استخدام الأجزاء (Fragments) في React
- المداخل (Portals) في React
- حدود الأخطاء
- مكونات الويب
- المكونات ذات الترتيب الأعلى
- تمرير المراجع
- خاصيات التصيير
- تكامل React مع المكتبات الأخرى
- سهولة الوصول
- تقسيم الشيفرة
- الوضع الصارم (Strict Mode)