كتابة واجهة برمجة تطبيقات لمكونات React ، الجزء 3: ترتيب الدعائم هو المهم

كتابة واجهة برمجة تطبيقات لمكونات React ، الجزء 1: لا تقم بإنشاء الدعائم المتعارضة

كتابة واجهة برمجة تطبيقات لمكونات التفاعل ، الجزء 2: إعطاء أسماء للسلوك ، وليس التفاعل

كتابة واجهة برمجة تطبيقات لمكونات React ، الجزء 3: ترتيب الدعائم هو المهم

كتابة واجهة برمجة تطبيقات لمكونات التفاعل ، الجزء 4: احذر من Apropacalypse!

كتابة واجهة برمجة تطبيقات لمكونات التفاعل ، الجزء 5: مجرد استخدام التكوين

نكتب واجهة برمجة التطبيقات لمكونات React ، الجزء 6: نخلق التواصل بين المكونات

لنبدأ بمكون React بسيط يعرض علامة ربط:


صلة


<Link href="sid.studio">Click me</Link> //   : <a href="sid.studio" class="link">Click me</a> 

إليك ما يشبه رمز المكون:


 const Link = props => { return ( <a href={props.href} className="link"> {props.children} </a> ) } 

نريد أيضًا أن نكون قادرين على إضافة سمات html إلى العنصر ، مثل id ، target ، title ، data-attr ، إلخ.


نظرًا لوجود العديد من سمات HTML ، يمكننا فقط تمرير جميع الدعائم وإضافة الخصائص التي نحتاجها (مثل className )


(ملاحظة: يجب ألا تتجاوز السمات التي توصلت إليها لهذا المكون غير الموجود في مواصفات HTML)


في هذه الحالة ، يمكنك ببساطة استخدام className


 const Link = props => { /*    (spread ),     ( ) */ return <a {...props} className="link" /> } 

هذا هو المكان الذي تحصل عليه مثيرة للاهتمام.


يبدو أن كل شيء على ما يرام عندما يمر شخص ما id أو target :


 <Link href="sid.studio" id="my-link">Click me</Link> //   : <a href="sid.studio" id="my-link" class="link">Click me</a> 

ولكن ماذا يحدث عندما يمر شخص ما className ؟


صلة


 <Link href="sid.studio" className="red-link">Click me</Link> //   : <a href="sid.studio" class="link">Click me</a> 

حسنا ، لم يحدث شيء. رد تجاهل تماما الطبقة المخصصة. دعنا نعود إلى الوظيفة:


 const Link = props => { return <a {...props} className="link" /> } 

حسنًا ، دعنا نتخيل كيف يجمع هذا ...props ، الكود أعلاه مكافئ لهذا:


 const Link = props => { return ( <a href="sid.studio" className="red-link" className="link" > Click me </a> ) } 

رؤية الصراع؟ هناك نوعان className . كيف تتعامل React مع هذا؟


حسنا ، رد فعل لا يفعل شيئا. بابل يفعل!


تذكر أن React.createElement "ينتج" React.createElement . يتم تحويل الدعائم إلى كائن ويتم تمريرها كوسيطة. لا تدعم الكائنات مفاتيح مكررة ، وبالتالي فإن className الثاني سوف className الكتابة الأولى.


 const Link = props => { return React.createElement( 'a', { className: 'link', href: 'sid.studio' }, 'Click me' ) } 



حسنًا ، بعد أن علمنا بالمشكلة ، كيف يمكننا حلها؟


من المفيد أن نفهم أن هذا الخطأ قد حدث بسبب تعارض الأسماء ، وهذا يمكن أن يحدث مع أي دعم ، وليس فقط مع className . لذلك يعتمد القرار على السلوك الذي تريد تنفيذه.


هناك ثلاثة سيناريوهات محتملة:


  1. يجب أن يكون المطور الذي يستخدم المكون الخاص بنا قادراً على تجاوز قيمة prop الافتراضية.
  2. لا نريد السماح للمطور بتغيير بعض الدعائم
  3. يجب أن يكون المطور قادراً على إضافة قيم مع الحفاظ على القيمة الافتراضية.

دعنا نفرقهم في وقت واحد.


1. يجب أن يكون المطور الذي يستخدم المكون الخاص بنا قادراً على تجاوز قيمة prop الافتراضية


هذا هو السلوك الذي تتوقعه عادةً من السمات الأخرى - id ، title ، إلخ.


كثيرا ما نرى إعداد test id في الكون (نظام التصميم الذي أعمل عليه). يتلقى كل مكون معرفًا افتراضيًا data-test-id ، ويريد المطورون في بعض الأحيان إلحاق معرف الاختبار الخاص بهم بدلاً من ذلك ، للإشارة إلى استخدام محدد.


إليك إحدى حالات الاستخدام هذه:


فتات الخبز


 const Breadcrumb = () => ( <div className="breadcrumb" data-test-id="breadcrumb"> <Link data-test-id="breadcrumb.link">Home</Link> <Link data-test-id="breadcrumb.link">Parent</Link> <Link data-test-id="breadcrumb.link">Page</Link> </div> ) 

يستخدم تطبيق Breadcrumb الرابط ، لكنك تريد أن تكون قادرًا على استخدامه في الاختبارات ذات data-test-id الأكثر تحديدًا. هناك عيب فيه.


في معظم الحالات ، يجب أن تكون الدعائم المخصصة لها الأسبقية على الدعائم الافتراضية.


في الممارسة العملية ، هذا يعني أن الدعائم الافتراضية يجب أن تبدأ أولاً ، ثم {...props} لتجاوزها.


 const Link = props => { return ( <a className="link" data-test-id="link" {...props} /> ) } 

تذكر أن المظهر الثاني data-test-id (من الدعائم) سيتخطى الأول (افتراضيًا). لذلك ، عندما يقوم مطور بإرفاق data-test-id الخاص به أو className ، فإنه يتخطى ذلك الذي كان افتراضيًا:


 1. <Link href="sid.studio">Click me</Link> 2. <Link href="sid.studio" data-test-id="breadcrumb.link">Click me</Link> //   : 1. <a class="link" href="sid.studio" data-test-id="link">Click me</a> 2. <a class="link" href="sid.studio" data-test-id="breadcrumb.link">Click me</a> 

يمكننا أن نفعل الشيء نفسه مع className :


أحمر الارتباط


 <Link href="sid.studio" className="red-link">Click me</Link> //   : <a href="sid.studio" class="red-link" data-test-id="link">Click me</a> 

يبدو غريباً إلى حد ما ، لست متأكدًا من أننا يجب أن نسمح بذلك! دعنا نتحدث عن هذا أبعد من ذلك.


2. لا نريد السماح للمطور بتغيير بعض الدعائم


لنفترض أننا لا نريد للمطورين تغيير المظهر (عبر className ) ، لكننا لا نمانع من قيامهم بتغيير الدعائم الأخرى ، مثل id data-test-id ، إلخ.


يمكننا القيام بذلك عن طريق طلب ترتيب سماتنا:


 const Link = props => { return ( <a data-test-id="link" {...props} className="link" /> ) } 

تذكر أن السمة الموجودة على اليمين ستتجاوز السمة الموجودة على اليسار. وبالتالي ، يمكن إعادة تعريف كل شيء قبل {...props} ، لكن لا يمكن إعادة تعريف كل شيء بعده.


لتبسيط عمل المطورين ، يمكنك عرض تحذير بأنه لا يمكنك تحديد className الخاص بك.


أحب إنشاء الدعائم الخاصة بالتحقق من النوع الخاصة بهذا:


 Link.PropTypes = { className: function(props) { if (props.className) { return new Error( `  className  Link,      ` ) } } } 

لديّ فيديو يتحدث عن التحقق من أنواع الدعائم المخصصة ، في حال كنت مهتمًا بكيفية كتابتها.


الآن ، عندما يحاول المطور تجاوز className ، لن ينجح ذلك ، وسيتلقى المطور تحذيرًا.


صلة


 <Link href="sid.studio" className="red-link">Click me</Link> //   : <a href="sid.studio" class="link">Click me</a> 

 :   :   className  Link,       

بصراحة ، كان علي استخدام هذا القالب مرة واحدة أو مرتين فقط. عادة ما تثق في المطور باستخدام المكون الخاص بك.


مما يقودنا إلى المشاركة.


3. يجب أن يكون المطور قادرًا على إضافة قيم مع الحفاظ على القيمة الافتراضية


ربما هذا هو حالة الاستخدام الأكثر شيوعًا للفصول.


صلة


 <Link href="sid.studio" className="underline">Click me</Link> //   : <a href="sid.studio" class="link underline">Click me</a> 

يبدو التنفيذ كالتالي:


 const Link = props => { /*  className   */ const { className, otherProps } = props /*     */ const classes = 'link ' + className return ( <a data-test-id="link" className={classes} {...otherProps} /*     */ /> ) } 

هذا القالب مفيد أيضًا في قبول معالجات الأحداث (على سبيل المثال ، onClick ) لمكون به بالفعل.


تحول


 <Switch onClick={value => console.log(value)} /> 

إليك ما يبدو عليه تنفيذ هذا المكون:


 class Switch extends React.Component { state = { enabled: false } onToggle = event => { /*      */ this.setState({ enabled: !this.state.enabled }) /*       */ if (typeof this.props.onClick === 'function') { this.props.onClick(event, this.state.enabled) } } render() { /*        ️ */ return <div class="toggler" onClick={this.onToggle} /> } } 

هناك طريقة أخرى لتجنب اشتباكات الأسماء في معالجات الأحداث ، والتي وصفتها في واجهة برمجة تطبيقات الكتابة لمكونات التفاعل ، الجزء 2: إعطاء أسماء للسلوك ، وليس طرق التفاعل .




لكل سيناريو ، يمكنك استخدام طرق مختلفة.


  1. معظم الوقت: يجب أن يكون المطور قادرًا على تغيير قيمة prop ، التي تم تعيين قيمتها افتراضيًا
  2. عادةً بالنسبة للأنماط ومعالجات الأحداث: يجب أن يكون المطور قادرًا على إضافة قيمة على القيمة الافتراضية
  3. حالة نادرة عندما تحتاج إلى الحد من تصرفات المطور: لا يُسمح للمطور بتغيير السلوك ، فيجب عليك تجاهل قيمه ، وفي الوقت نفسه ، إظهار التحذيرات

Source: https://habr.com/ru/post/ar459380/


All Articles