الفرق بين المراجعتين لصفحة: «React/forwarding refs»
Kinan-mawed (نقاش | مساهمات) لا ملخص تعديل |
تحديث |
||
(4 مراجعات متوسطة بواسطة 3 مستخدمين غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:تمرير المراجع}}</noinclude> | <noinclude>{{DISPLAYTITLE:تمرير المراجع في React}}</noinclude> | ||
تمرير المراجع هو تقنية لتمرير مرجع <code>ref</code> تلقائيًّا من مكوّن إلى عناصره الأبناء. لا يكون هذا ضروريًّا بشكل نموذجي لمعظم مكوّنات التطبيق، ولكن قد يكون مفيدًا لبعض أنواع المكوّنات، خاصّة مكتبات المكوّنات القابلة لإعادة الاستخدام. سنتحدث في هذه الصفحة عن أشيع الحالات التي نحتاج فيها تمرير المراجع. | تمرير المراجع هو تقنية لتمرير مرجع <code>[[React/refs and the dom|ref]]</code> تلقائيًّا من مكوّن إلى عناصره الأبناء. لا يكون هذا ضروريًّا بشكل نموذجي لمعظم مكوّنات التطبيق، ولكن قد يكون مفيدًا لبعض أنواع المكوّنات، خاصّة مكتبات المكوّنات القابلة لإعادة الاستخدام. سنتحدث في هذه الصفحة عن أشيع الحالات التي نحتاج فيها تمرير المراجع. | ||
== تمرير المراجع إلى مكونات DOM == | == تمرير المراجع إلى مكونات DOM == | ||
سطر 12: | سطر 12: | ||
} | } | ||
</syntaxhighlight>تُخفي مكوّنات React تفاصيلها التنفيذية، بما في ذلك الناتج المُصيَّر. لا تحتاج المكوّنات الأخرى التي تستخدم المكوّن <code>FancyButton</code> عادةً إلى الحصول على مرجع <code>ref</code> لعنصر الزر <code>button</code> الداخلي. يكون هذا جيّدًا لأنّه يمنع المكوّنات من الاعتماد كثيرًا على بنية DOM للمكوّنات الأخرى. | </syntaxhighlight>تُخفي مكوّنات React تفاصيلها التنفيذية، بما في ذلك الناتج المُصيَّر. لا تحتاج المكوّنات الأخرى التي تستخدم المكوّن <code>FancyButton</code> عادةً إلى [[React/refs and the dom|الحصول على مرجع]] <code>ref</code> لعنصر الزر <code>button</code> الداخلي. يكون هذا جيّدًا لأنّه يمنع المكوّنات من الاعتماد كثيرًا على بنية DOM للمكوّنات الأخرى. | ||
قد يكون مثل هذا التغليف مرغوبًا في مكوّنات التطبيق مثل <code>FeedStory</code> أو <code>Comment</code>، ولكنّه قد يكون غير ملائم بالنسبة للمكوّنات القابلة لإعادة الاستخدام بكثرة مثل <code>FancyButton</code> أو <code>MyTextInput</code>. تميل هذه المكوّنات لاستخدامها عبر التطبيق بنفس الطريقة مثل الزر <code>button</code> وحقل الإدخال <code>input</code> في DOM، وقد يكون الوصول إلى عقد DOM الخاصّة بها أمرًا لا بُدّ منه لإدارة التركيز، أو الاختيار، أو التحريكات. | قد يكون مثل هذا التغليف مرغوبًا في مكوّنات التطبيق مثل <code>FeedStory</code> أو <code>Comment</code>، ولكنّه قد يكون غير ملائم بالنسبة للمكوّنات القابلة لإعادة الاستخدام بكثرة مثل <code>FancyButton</code> أو <code>MyTextInput</code>. تميل هذه المكوّنات لاستخدامها عبر التطبيق بنفس الطريقة مثل الزر <code>button</code> وحقل الإدخال <code>input</code> في DOM، وقد يكون الوصول إلى عقد DOM الخاصّة بها أمرًا لا بُدّ منه لإدارة التركيز، أو الاختيار، أو التحريكات. | ||
تمرير المراجع هو عبارة عن ميزة تسمح لبعض المكوّنات باستقبال مرجع <code>ref</code> وتمريره إلى المستويات الأدنى إلى المكوّنات الأبناء. | '''تمرير المراجع هو عبارة عن ميزة تسمح لبعض المكوّنات باستقبال مرجع <code>ref</code> وتمريره إلى المستويات الأدنى إلى المكوّنات الأبناء.''' | ||
يستخدم المكوّن <code>FancyButton</code> في المثال التالي <code>React.forwardRef</code> للحصول على المرجع <code>ref</code> المُمرَّر له، ومن ثمّ يُمرِّره إلى الزر <code>button</code> الذي يُصيِّره:<syntaxhighlight lang="javascript"> | يستخدم المكوّن <code>FancyButton</code> في المثال التالي <code>React.forwardRef</code> للحصول على المرجع <code>ref</code> المُمرَّر له، ومن ثمّ يُمرِّره إلى الزر <code>button</code> الذي يُصيِّره:<syntaxhighlight lang="javascript"> | ||
سطر 32: | سطر 32: | ||
وهذا شرح مُفصَّل عمّا حدث في المثال السابق: | وهذا شرح مُفصَّل عمّا حدث في المثال السابق: | ||
# أنشأنا | # [[React/refs and the dom|أنشأنا مرجعًا]] <code>ref</code> عن طريق استدعاء <code>React.createRef</code> وتعيينه إلى المتغيّر ref. | ||
# مرّرنا المرجع <code>ref</code> إلى المكوّن <code><FancyButton ref={ref}></code> عن طريق تحديده كخاصيّة JSX. | # مرّرنا المرجع <code>ref</code> إلى المكوّن <code><FancyButton ref={ref}></code> عن طريق تحديده كخاصيّة JSX. | ||
# تُمرِّر React المرجع <code>ref</code> إلى الدالة <code>(props, ref) => ...</code> الموجودة بداخل التابع <code>forwardRef</code> كوسيط ثانٍ له. | # تُمرِّر React المرجع <code>ref</code> إلى الدالة <code>(props, ref) => ...</code> الموجودة بداخل التابع <code>forwardRef</code> كوسيط ثانٍ له. | ||
سطر 47: | سطر 47: | ||
== تمرير المراجع في المكونات ذات الترتيب الأعلى == | == تمرير المراجع في المكونات ذات الترتيب الأعلى == | ||
تكون هذه الطريقة مفيدة بشكل خاص مع المكوّنات ذات الترتيب الأعلى (higher-order components واختصارًا HOCs). فلنبدأ بمثال عن المكوّنات ذات الترتيب الأعلى والذي يعرض خاصيّات المكوّنات في الكونسول:<syntaxhighlight lang="javascript"> | تكون هذه الطريقة مفيدة بشكل خاص مع [[React/higher order components|المكوّنات ذات الترتيب الأعلى]] (higher-order components واختصارًا HOCs). فلنبدأ بمثال عن المكوّنات ذات الترتيب الأعلى والذي يعرض خاصيّات المكوّنات في الكونسول:<syntaxhighlight lang="javascript"> | ||
function logProps(WrappedComponent) { | function logProps(WrappedComponent) { | ||
class LogProps extends React.Component { | class LogProps extends React.Component { | ||
سطر 62: | سطر 62: | ||
return LogProps; | return LogProps; | ||
} | } | ||
</syntaxhighlight>يُمرِّر المكوّن <code>logProps</code> كل الخاصيّات عبر المكوّن الذي يُغلِّفه، لذا سيكون الناتج المُصيَّر نفسه. فمثلًا نستطيع استخدام هذا المكوّن ذو الترتيب الأعلى لعرض جميع الخاصيّات المُمرَّرة إلى المكوّن <code>FancyButton</code>:<syntaxhighlight lang="javascript"> | </syntaxhighlight>يُمرِّر المكوّن <code>logProps</code> كل الخاصيّات عبر المكوّن الذي يُغلِّفه، لذا سيكون الناتج المُصيَّر نفسه. فمثلًا نستطيع استخدام هذا المكوّن ذو الترتيب الأعلى لعرض جميع الخاصيّات المُمرَّرة إلى المكوّن <code>FancyButton</code>:<syntaxhighlight lang="javascript"> | ||
class FancyButton extends React.Component { | class FancyButton extends React.Component { | ||
سطر 157: | سطر 156: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== انظر أيضًا == | |||
* [[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/context|استخدام السياق (Context) في React]] | |||
* [[React/fragments|استخدام الأجزاء (Fragments) في React]] | |||
* [[React/portals|المداخل (Portals) في React]] | |||
* [[React/error boundaries|حدود الأخطاء]] | |||
* [[React/web components|مكونات الويب]] | |||
* [[React/higher order components|المكونات ذات الترتيب الأعلى]] | |||
* [[React/render props|خاصيات التصيير]] | |||
* [[React/integrating with other libraries|تكامل React مع المكتبات الأخرى]] | |||
* [[React/accessibility|سهولة الوصول]] | |||
* [[React/code splitting|تقسيم الشيفرة]] | |||
* [[React/strict mode|الوضع الصارم (Strict Mode)]] | |||
== مصادر== | |||
*[https://reactjs.org/docs/forwarding-refs.html صفحة تمرير المراجع في توثيق React الرسمي]. | |||
[[تصنيف:React]] | |||
[[تصنيف:React Advanced Guides]] |
المراجعة الحالية بتاريخ 18:22، 3 نوفمبر 2020
تمرير المراجع هو تقنية لتمرير مرجع ref
تلقائيًّا من مكوّن إلى عناصره الأبناء. لا يكون هذا ضروريًّا بشكل نموذجي لمعظم مكوّنات التطبيق، ولكن قد يكون مفيدًا لبعض أنواع المكوّنات، خاصّة مكتبات المكوّنات القابلة لإعادة الاستخدام. سنتحدث في هذه الصفحة عن أشيع الحالات التي نحتاج فيها تمرير المراجع.
تمرير المراجع إلى مكونات DOM
فلنأخذ مثال عن المكوّن FancyButton
والذي يُصيِّر زر button
في DOM:
function FancyButton(props) {
return (
<button className="FancyButton">
{props.children}
</button>
);
}
تُخفي مكوّنات React تفاصيلها التنفيذية، بما في ذلك الناتج المُصيَّر. لا تحتاج المكوّنات الأخرى التي تستخدم المكوّن FancyButton
عادةً إلى الحصول على مرجع ref
لعنصر الزر button
الداخلي. يكون هذا جيّدًا لأنّه يمنع المكوّنات من الاعتماد كثيرًا على بنية DOM للمكوّنات الأخرى.
قد يكون مثل هذا التغليف مرغوبًا في مكوّنات التطبيق مثل FeedStory
أو Comment
، ولكنّه قد يكون غير ملائم بالنسبة للمكوّنات القابلة لإعادة الاستخدام بكثرة مثل FancyButton
أو MyTextInput
. تميل هذه المكوّنات لاستخدامها عبر التطبيق بنفس الطريقة مثل الزر button
وحقل الإدخال input
في DOM، وقد يكون الوصول إلى عقد DOM الخاصّة بها أمرًا لا بُدّ منه لإدارة التركيز، أو الاختيار، أو التحريكات.
تمرير المراجع هو عبارة عن ميزة تسمح لبعض المكوّنات باستقبال مرجع ref
وتمريره إلى المستويات الأدنى إلى المكوّنات الأبناء.
يستخدم المكوّن FancyButton
في المثال التالي React.forwardRef
للحصول على المرجع ref
المُمرَّر له، ومن ثمّ يُمرِّره إلى الزر button
الذي يُصيِّره:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// تستطيع الآن الحصول على مرجع بشكل مباشر للزر button
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
بهذه الطريقة تستطيع المكوّنات التي تستخدم المكوّن FancyButton
الحصول على مرجع للزر button
والوصول إليه عند الضرورة كما لو أنّها تستخدم الزر بشكل مباشر.
وهذا شرح مُفصَّل عمّا حدث في المثال السابق:
- أنشأنا مرجعًا
ref
عن طريق استدعاءReact.createRef
وتعيينه إلى المتغيّر ref. - مرّرنا المرجع
ref
إلى المكوّن <FancyButton ref={ref}>
عن طريق تحديده كخاصيّة JSX. - تُمرِّر React المرجع
ref
إلى الدالة(props, ref) => ...
الموجودة بداخل التابعforwardRef
كوسيط ثانٍ له. - نُمرِّر هذا المرجع إلى الزر
<button ref={ref}>
عن طريق تحديده كخاصيّة JSX. - عند ربط المرجع
ref
ستُشيرref.current
إلى عقدة DOM الخاصّة بالزر<button>
.
ملاحظة: يُوجَد الوسيط الثاني ref
فقط عندما تُعرِّف مكوّن باستخدام الاستدعاء React.forwardRef
. لا تستقبل مكوّنات الأصناف أو الدوال الاعتيادية الوسيط ref
، وهو ليس متوفر ضمن الخاصيّات حتى.
لا يكون تمرير المراجع محدودًا فقط لمكوّنات DOM، فبإمكانك تمرير المراجع إلى نُسَخ مكوّنات الأصناف أيضًا.
ملاحظة بالنسبة لمكتبات المكونات
عندما تبدأ باستخدام forwardRef
في مكتبة مكوّناتك الخاصّة، فيجب عليك معاملتها كتغيير جذري وإصدار رئيسي جديد من مكتبتك، وذلك لأنّه من الغالب أنّ مكتبتك لديها سلوك ملحوظ مختلف تمامًا (مثل الأشياء التي نُعيِّن إليها المراجع، والأنواع المستخرجة) وقد يُعطِّل هذا التطبيقات والمكتبات الأخرى التي تعتمد على السلوك القديم.
لا نوصي بتطبيق React.forwardRef
بشكلٍ شرطي عند وجودها لنفس الأسباب، فهي تغيّر سلوك مكتبتك وقد تُعطِّل تطبيقات مستخدميك عند تحديثهم لمكتبة React بحد ذاتها.
تمرير المراجع في المكونات ذات الترتيب الأعلى
تكون هذه الطريقة مفيدة بشكل خاص مع المكوّنات ذات الترتيب الأعلى (higher-order components واختصارًا HOCs). فلنبدأ بمثال عن المكوّنات ذات الترتيب الأعلى والذي يعرض خاصيّات المكوّنات في الكونسول:
function logProps(WrappedComponent) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return LogProps;
}
يُمرِّر المكوّن logProps
كل الخاصيّات عبر المكوّن الذي يُغلِّفه، لذا سيكون الناتج المُصيَّر نفسه. فمثلًا نستطيع استخدام هذا المكوّن ذو الترتيب الأعلى لعرض جميع الخاصيّات المُمرَّرة إلى المكوّن FancyButton
:
class FancyButton extends React.Component {
focus() {
// ...
}
// ...
}
// بدلا من استخراج FancyButton
// نستخرج LogProps
/// سيصير المكون FancyButton رغم ذلك
export default logProps(FancyButton);
هنالك شيء واحد يجب الانتباه له في المثال السابق وهو عدم القدرة على تمرير المراجع وذلك لأنّ ref
ليست خاصيّة مثل المفتاح key
مثلًا، حيث تُعامِلها React بشكلٍ مختلف. إن أضفت مرجعًا إلى المكوّن ذو الترتيب الأعلى فسيُشير إلى المكوّن الخارجي الحاوي وليس المكوّن المُغلّف.
هذا يعني أنّ المراجع المُخصَّصة من أجل المكوّن FancyButton
سترتبط فعليًّا بالمكوّن LogProps
:
import FancyButton from './FancyButton';
const ref = React.createRef();
// المكوّن FancyButton الذي استوردناه في المكوّن LogProps
// على الرغم من بقاء الناتج نفسه
// سيشير المرجع إلى LogProps بدلًا من المكوّن FancyButton الداخلي
// يعني هذا عدم قدرتنا على استدعاء ref.current.focus()
<FancyButton
label="انقر هنا"
handleClick={handleClick}
ref={ref}
/>;
لحسن الحظ نستطيع تمرير المراجع إلى المكوّن الداخلي FancyButton
باستخدام React.forwardRef
والتي تقبل دالة تصيير تستقبل مُعامِلات للخاصيّات props
والمرجع ref
وتُعيد عقدة React، على سبيل المثال:
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// تعين الخاصية المخصصة forwardedRef كمرجع
return <Component ref={forwardedRef} {...rest} />;
}
}
// لاحظ أن المعامل الثاني ref زودتنا به React.forwardRef
// نستطيع تمريره إلى LogProps كخاصية اعتيادية forwardedRef
// وبعدها يمكن ربطه بالمكون
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
عرض اسم مخصص في أدوات التطوير
يقبل React.forwardRef
دالة تصيير. تستخدم أدوات تطوير React هذه الدالة لتحديد ماذا ستعرض من أجل المكوّن الذي يُمرِّر المرجع.
على سبيل المثال سيظهر المكوّن التالي بالاسم "ForwardRef"
في أدوات التطوير:
const WrappedComponent = React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
إن سميت دالة التصيير فستُضمّن أدوات التطوير اسمها (على الشكل "ForwardRef(myFunction)"
):
const WrappedComponent = React.forwardRef(
function myFunction(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
);
بإمكانك أيضًا تعيين الخاصيّة displayName
لتضمين المكوّن الذي تُغلِّفه:
function logProps(Component) {
class LogProps extends React.Component {
// ...
}
function forwardRef(props, ref) {
return <LogProps {...props} forwardedRef={ref} />;
}
// إعطاء هذا المكون اسمًا أكثر فائدة في أدوات التطوير
// e.g. "ForwardRef(logProps(MyComponent))"
const name = Component.displayName || Component.name;
forwardRef.displayName = `logProps(${name})`;
return React.forwardRef(forwardRef);
}
انظر أيضًا
- شرح JSX بالتفصيل
- التحقق من الأنواع الثابتة
- التحقق من الأنواع باستخدام PropTypes
- استخدام المراجع مع DOM
- المكونات غير المضبوطة
- تحسين الأداء
- React بدون ES6
- React بدون JSX
- المطابقة (Reconciliation)
- استخدام السياق (Context) في React
- استخدام الأجزاء (Fragments) في React
- المداخل (Portals) في React
- حدود الأخطاء
- مكونات الويب
- المكونات ذات الترتيب الأعلى
- خاصيات التصيير
- تكامل React مع المكتبات الأخرى
- سهولة الوصول
- تقسيم الشيفرة
- الوضع الصارم (Strict Mode)