استخدام المراجع مع DOM
These docs are old and won’t be updated. Go to react.dev for the new React docs.
These new documentation pages teach modern React and include live examples:
تُزوّدنا المراجع بطريقة للوصول إلى عقد DOM أو عناصر React المُنشأة باستخدام التابع render.
تكون الخاصيات في تدفق بيانات React النموذجي هي الطريقة الوحيدة التي يتواصل بها المكون الأب مع أبنائه. وللتعديل على الإبن يتم اعادة تصيير المكون بخاصيات جديدة. على الرغم من ذلك ، في بعض الحالات التي قد تحتاج الى اجراء تعديل على مكون إبن بشكل إجباري خارج نطاق التدفق المعتاد. من الممكن ان يكون المكون الإبن المُراد تعديله نسخة instance من مُكوّن React ، أو ان يكون عنصر DOM. في كلتا الحالتين توفر لنا React مفر للإلتفاف حول هذه الحالات.
متى تُستَخدم المراجع Refs
هنالك بعض الحالات المناسبة لاستخدام المراجع refs وهي:
- التحكم بالتركيز على العناصر ، وتحديد النصوص ، والتحكم بتشغيل الوسائط.
- إطلاق التحريكات الإجباريّة.
- التكامل مع مكتبات 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} />; }
}
الوصول للمراجع
عند تمرير مرجع ref إلى عنصر في التابع render
، يُصبح المرجع إلى العُقدة قابلاً للوصول باستخدام الخاصية current
للمرجع.
const node = this.myRef.current;
تختلف قيمة المرجع بناءً على نوع العقدة:
- عند استخدام الخاصيّة
ref
على عنصر HTML فإن المرجعref
المنشأ في الدالة البانية باستخدامReact.createRef()
يستقبل عنصر DOM الأساسي كخاصية حاليةcurrent
. - عند استخدام خاصية المرجع
ref
على مكوِّن صنف مُخصص فأن الكائن المرجعref
يستقبل نسخة من المكون المُحَمَّل كخاصية حاليةcurrent
. - لا يُمكنك استخدام الخاصيّة
ref
على المُكوِّنات المُعرَّفة كدوال لأنّها لا تملك نُسَخ.
الأمثلة أدناه توَضِح الفروقات.
إضافة مرجع إلى عنصر DOM
المثال التالي يستخدم خاصية المرجع ref
لتخزين مرجع لعفدة DOM:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef(); this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus(); }
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} /> <input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
سَتُعيِّن React الخاصية current
مع عنصر DOM عند تحميل المُكَوِّن و أعادة تعيينها الى null
عند إزالة تحميل المُكون. تحديثات المرجع ref
تحدث قبل خُطافات دورة حياة المُكوِّن componentDidMount
أو componentDidUpdate
.
إضافة مرجع إلى مُكوِّن الصنف
إن أردنا تغليف المكون CustomTextInput
أعلاه لمحاكاة النقر عليه فورًا بعد التحميل ، يمكننا أن نستخدم مرجع للوصول إلى حقل الإدخال المُخَصَّص و استدعاء تابعه 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 MyFunctionComponent() { return <input />;
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef(); }
render() {
// This will *not* work!
return (
<MyFunctionComponent ref={this.textInput} /> );
}
}
اذا كنت ترغب بالسماح باستخدام خاصية المرجع ref
لمُكونات الدّالة الخاصة بك، يمكنك استخدام forwardRef
(ربما بالتزامن مع useImperativeHandle
) أو يمكنك تحويل المكون الى صنف.
على أيّةِ حال ، يمكنك استخدام خاصية المرجع ref
داخل مُكون دالّة طالما كنت تُشير إلى عنصر DOM أو مُكون صنف:
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it const textInput = useRef(null);
function handleClick() {
textInput.current.focus(); }
return (
<div>
<input
type="text"
ref={textInput} /> <input
type="button"
value="Focus the text input"
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 = () => { // Focus the text input using the raw DOM API if (this.textInput) this.textInput.focus(); }; }
componentDidMount() {
// autofocus the input on mount
this.focusTextInput(); }
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={this.setTextInputRef} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput} />
</div>
);
}
}
ستستدعي React رد نداء المرجع ref
مع عنصر DOM عند تحميل المُكوِّن ، وتستدعيه مع null
عند إزالة تحميل المُكون. من المؤكَّد ان تكون المراجع مُحَدَّثة قَبلَ إطلاق التوابع 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 القديمة: مراجع السلاسل النصية strings
إن تعاملتَ مع React سابقًا فقد تكون مُعتادًا على واجهة برمجة التطبيق القديمة حيث كانت خاصيّة المرجع ref
عبارة عن سلسلة نصيّة string، مثل "textInput"
، ويتم الوصول إلى عقدة DOM عبر this.refs.textInput
. لا ننصح بفعل ذلك لأنّ مراجع السلاسل النصيّة strings لديها بعض المشاكل، وأصبحت مُهمَلة، ومن المحتمل أنّها ستُزال في الإصدارات القادمة.
ملاحظة
إن كنتَ تستخدم
this.refs.textInput
حاليًّا للوصول إلى المراجع، فأننا ننصح باستخدام إمّا نمط ردود النداء أو واجهة برمجة التطبيقcreateRef
عوضًا عن ذلك.
أخطار استخدام ردود نداء المراجع
إن كان رد نداء المرجع ref
مُعرَّفًا كدالّة سطريّة inline، فسيُستدعى مرتين خلال التحديثات، مرّة أولى مع القيمة null
ومرة أخرى مع عنصر DOM. ويحدث هذا بسبب إنشاء نسخة جديدة من الدالة مع كل تصيير، لذا تحتاج React إلى مسح المرجع القديم وإعداد واحد جديد. بإمكانك تجنّب ذلك عن طريق تعريف رد نداء المرجع ref
كتابع مربوط في الصنف، ولكن لاحظ أنّ هذا غير هام في معظم الحالات.