مكونات النظام الأعلى في رد الفعل

نشرنا مؤخرًا مواد عن وظائف الترتيب الأعلى في JavaScript تستهدف أولئك الذين يتعلمون JavaScript. المقالة التي نترجمها اليوم مخصصة للمطورين المبتدئين. ويركز على مكونات النظام الأعلى (HOC).



مبدأ DRY ومكونات النظام الأعلى في React


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

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


لوحة التحكم وتلميحات الأدوات

من أجل تنفيذ مثل هذه الوظيفة ، يمكنك استخدام العديد من الأساليب. لقد قررت القيام بذلك: حدد ما إذا كان المؤشر أعلى مكون فردي ، ثم قرر ما إذا كنت تريد إظهار تلميحًا له أم لا. هناك ثلاثة مكونات تحتاج إلى أن تكون مجهزة بوظائف مماثلة. هذه هي Info و TrendChart و DailyChart .

لنبدأ بمكون Info . الآن هو رمز SVG بسيط.

 class Info extends React.Component { render() {   return (     <svg       className="Icon-svg Icon--hoverable-svg"       height={this.props.height}       viewBox="0 0 16 16" width="16">         <path d="M9 8a1 1 0 0 0-1-1H5.5a1 1 0 1 0 0 2H7v4a1 1 0 0 0 2 0zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm4 5.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />     </svg>   ) } } 

نحتاج الآن إلى جعل هذا المكون قادرًا على تحديد ما إذا كان مؤشر الماوس فوقه أم لا. يمكنك استخدام فعاليات الماوس onMouseOut و onMouseOut لهذا الغرض. سيتم استدعاء الوظيفة التي تم تمريرها إلى onMouseOver إذا سقط مؤشر الماوس في منطقة المكون ، وسيتم استدعاء الوظيفة التي تم تمريرها إلى onMouseOut عندما يترك المؤشر المكون. من أجل تنظيم كل هذا بطريقة مقبولة في React ، نضيف خاصية hovering إلى المكون المخزن في الحالة ، مما يسمح لنا بإعادة عرض المكون عن طريق إظهار تلميح الأداة أو إخفائه إذا تغيرت هذه الخاصية.

 class Info extends React.Component { state = { hovering: false } mouseOver = () => this.setState({ hovering: true }) mouseOut = () => this.setState({ hovering: false }) render() {   return (     <>       {this.state.hovering === true         ? <Tooltip id={this.props.id} />         : null}       <svg         onMouseOver={this.mouseOver}         onMouseOut={this.mouseOut}         className="Icon-svg Icon--hoverable-svg"         height={this.props.height}         viewBox="0 0 16 16" width="16">           <path d="M9 8a1 1 0 0 0-1-1H5.5a1 1 0 1 0 0 2H7v4a1 1 0 0 0 2 0zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm4 5.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />       </svg>     </>   ) } } 

اتضح بشكل جيد. الآن نحن بحاجة إلى إضافة نفس الوظيفة إلى مكونين آخرين - TrendChart و DailyChart . تعمل الآلية المذكورة أعلاه لمكون Info بشكل جيد ، ولا يلزم إصلاح ما لم يتم كسره ، لذا دعنا نعيد إنشاء نفسه في المكونات الأخرى باستخدام نفس الرمز. قم بإعادة تدوير التعليمات البرمجية لمكون TrendChart .

 class TrendChart extends React.Component { state = { hovering: false } mouseOver = () => this.setState({ hovering: true }) mouseOut = () => this.setState({ hovering: false }) render() {   return (     <>       {this.state.hovering === true         ? <Tooltip id={this.props.id}/>         : null}       <Chart         type='trend'         onMouseOver={this.mouseOver}         onMouseOut={this.mouseOut}       />     </>   ) } } 

ربما فهمت بالفعل ما يجب فعله بعد ذلك. ويمكن القيام DailyChart نفسه مع المكون الأخير - DailyChart .

 class DailyChart extends React.Component { state = { hovering: false } mouseOver = () => this.setState({ hovering: true }) mouseOut = () => this.setState({ hovering: false }) render() {   return (     <>       {this.state.hovering === true         ? <Tooltip id={this.props.id}/>         : null}       <Chart         type='daily'         onMouseOver={this.mouseOver}         onMouseOut={this.mouseOut}       />     </>   ) } } 

الآن كل شيء جاهز. ربما تكون قد كتبت بالفعل شيئًا مشابهًا على React. هذا ، بالطبع ، ليس أسوأ رمز في العالم ، لكنه لا يتبع مبدأ DRY بشكل جيد. كما ترون ، من خلال تحليل رمز المكون ، نكرر ، في كل واحد منهم ، نفس المنطق.

يجب أن تصبح المشكلة التي تواجهنا واضحة للغاية الآن. هذا رمز مكرر. لحلها ، نريد التخلص من الحاجة إلى نسخ نفس الرمز في الحالات التي يحتاج فيها مكون جديد بالفعل إلى ما قمنا بتطبيقه بالفعل. كيفية حلها؟ قبل أن نتحدث عن هذا ، سنركز على العديد من مفاهيم البرمجة التي ستسهل إلى حد كبير فهم الحل المقترح هنا. نحن نتحدث عن رد الاتصال ووظائف الترتيب الأعلى.

وظائف ترتيب أعلى


وظائف JavaScript هي كائنات من الدرجة الأولى. هذا يعني أنها ، مثل الكائنات أو المصفوفات أو السلاسل ، يمكن تعيينها لمتغيرات أو تمريرها إلى دالات كوسيطة أو إرجاعها من دالات أخرى.

 function add (x, y) { return x + y } function addFive (x, addReference) { return addReference(x, 5) } addFive(10, add) // 15 

إذا لم تكن معتادًا على هذا السلوك ، فقد يبدو الرمز أعلاه غريبًا بالنسبة لك. لنتحدث عما يحدث هنا. وبالتحديد ، نقوم بتمرير وظيفة add إلى وظيفة addFive كوسيطة ، addReference تسميتها إلى addReference ثم نسميها.

عند استخدام مثل هذه الإنشاءات ، تُسمى الدالة التي يتم تمريرها كوسيطة إلى أخرى باسم رد الاتصال (وظيفة رد الاتصال) ، وتسمى الوظيفة التي تتلقى وظيفة أخرى كوسيطة بوظيفة أعلى مرتبة.

تسمية الكيانات في البرمجة مهمة ، لذلك هنا هو نفس الرمز المستخدم الذي يتم فيه تغيير الأسماء وفقًا للمفاهيم التي تمثلها.

 function add (x,y) { return x + y } function higherOrderFunction (x, callback) { return callback(x, 5) } higherOrderFunction(10, add) 

يجب أن يبدو هذا النمط مألوفًا لك. والحقيقة هي أنك إذا استخدمت ، على سبيل المثال ، طرق صفيف جافا سكريبت ، وعملت مع jQuery أو Lodash ، فأنت قد استخدمت بالفعل وظائف عالية المستوى وعمليات رد.

 [1,2,3].map((i) => i + 5) _.filter([1,2,3,4], (n) => n % 2 === 0 ); $('#btn').on('click', () => console.log('Callbacks are everywhere') ) 

دعونا نعود إلى مثالنا. ماذا لو ، بدلاً من إنشاء وظيفة addFive فقط ، نريد إنشاء وظيفة addTwenty ، و addTwenty ، وغيرها مثل ذلك. بالنظر إلى كيفية addFive وظيفة addFive ، سيتعين علينا نسخ addFive وتغييرها لإنشاء الوظائف المذكورة أعلاه بناءً عليها.

 function add (x, y) { return x + y } function addFive (x, addReference) { return addReference(x, 5) } function addTen (x, addReference) { return addReference(x, 10) } function addTwenty (x, addReference) { return addReference(x, 20) } addFive(10, add) // 15 addTen(10, add) // 20 addTwenty(10, add) // 30 

وتجدر الإشارة إلى أن الكود الخاص بنا لم يكن كابوسًا جدًا ، ولكن من الواضح أن العديد من الأجزاء فيه متكررة. هدفنا هو أن نتمكن من إنشاء العديد من الوظائف التي تضيف أرقامًا معينة إلى الأرقام التي تم تمريرها إليها ( addFive و addTen و addTwenty وما إلى ذلك) بقدر ما نحتاج ، مع تقليل تكرار التعليمات البرمجية. ربما لتحقيق ذلك ، نحتاج إلى إنشاء وظيفة makeAdder ؟ يمكن أن تأخذ هذه الوظيفة رقمًا معينًا ورابطًا إلى وظيفة add . نظرًا لأن الغرض من هذه الوظيفة هو إنشاء وظيفة جديدة تضيف الرقم الذي تم تمريره إليها إلى الوظيفة المحددة ، يمكننا أن نجعل وظيفة makeAdder ترجع وظيفة جديدة تحتوي على رقم معين (مثل الرقم 5 في makeFive ) والتي يمكن أن تأخذ أرقامًا للإضافة إلى هذا الرقم.

نلقي نظرة على مثال على تنفيذ الآليات المذكورة أعلاه.

 function add (x, y) { return x + y } function makeAdder (x, addReference) { return function (y) {   return addReference(x, y) } } const addFive = makeAdder(5, add) const addTen = makeAdder(10, add) const addTwenty = makeAdder(20, add) addFive(10) // 15 addTen(10) // 20 addTwenty(10) // 30 

الآن يمكننا إنشاء العديد من add حسب الحاجة ، مع تقليل مقدار تكرار الكود.

إذا كان الأمر مثيرًا للاهتمام ، فإن المفهوم القائل بوجود وظيفة معينة تعالج وظائف أخرى بحيث يمكن استخدامها بمعلمات أقل من ذي قبل يُطلق عليه "التطبيق الجزئي للدالة". يستخدم هذا النهج في البرمجة الوظيفية. مثال على استخدامه هو أسلوب .bind المستخدم في JavaScript.

كل هذا جيد ، ولكن ما علاقة رد الفعل بالمشكلة المذكورة أعلاه المتمثلة في تكرار التعليمات البرمجية لمعالجة أحداث الماوس عند إنشاء مكونات جديدة تحتاج إلى هذه الميزة؟ والحقيقة هي أنه تمامًا مثل وظيفة الترتيب الأعلى ، makeAdder تقليل تكرار التعليمات البرمجية إلى الحد الأدنى ، فإن ما يُسمى "مكون الترتيب الأعلى" سيساعدنا في التعامل مع نفس المشكلة في تطبيق React. ومع ذلك ، هنا كل شيء سيبدو مختلفًا قليلاً. وبالتحديد ، بدلاً من مخطط العمل ، الذي تُرجع خلاله دالة الترتيب الأعلى وظيفة جديدة تستدعي رد الاتصال ، يمكن لمكون النظام الأعلى تنفيذ مخططه الخاص. أي أنه قادر على إرجاع مكون جديد يجعل مكونًا يلعب دور "رد الاتصال". ربما قلنا بالفعل الكثير من الأشياء ، لذلك حان الوقت للانتقال إلى الأمثلة.

وظيفة النظام الأعلى لدينا


تحتوي هذه الميزة على الميزات التالية:

  • إنها وظيفة.
  • تقبل كحجة رد اتصال.
  • تقوم بإرجاع دالة جديدة.
  • يمكن للدالة التي تقوم بإرجاعها استدعاء رد الاتصال الأصلي الذي تم تمريره إلى دالة الترتيب الأعلى الخاصة بنا.

 function higherOrderFunction (callback) { return function () {   return callback() } } 

عنصر النظام الأعلى لدينا


يمكن وصف هذا المكون على النحو التالي:

  • إنه مكون.
  • كحجة ، يأخذ عنصر آخر.
  • تقوم بإرجاع مكون جديد.
  • يمكن أن يعرض المكون الذي يقوم بإرجاع المكون الأصلي الذي تم تمريره إلى المكون ذي الترتيب الأعلى.

 function higherOrderComponent (Component) { return class extends React.Component {   render() {     return <Component />   } } } 

تنفيذ HOC


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

 state = { hovering: false } mouseOver = () => this.setState({ hovering: true }) mouseOut = () => this.setState({ hovering: false }) 

نظرًا لذلك ، نحتاج إلى مكون النظام الأعلى (دعنا نسميه بـ withHover ) لتغليف كود معالجة حدث الماوس ، ثم تمرير خاصية hovering إلى المكونات التي يعرضها. سيسمح لنا هذا بمنع تكرار الكود المقابل بوضعه في المكون withHover .

في النهاية ، هذا ما نريد تحقيقه. عندما نحتاج إلى مكون يحتاج إلى فكرة عن خاصية hovering الخاصة به ، يمكننا تمرير هذا المكون إلى مكون عالي الترتيب مع withHover . أي أننا نريد العمل مع المكونات كما هو موضح أدناه.

 const InfoWithHover = withHover(Info) const TrendChartWithHover = withHover(TrendChart) const DailyChartWithHover = withHover(DailyChart) 

بعد ذلك ، عندما يتم عرض ما withHover ، سيكون المكون المصدر الذي يتم hovering خاصية hovering .

 function Info ({ hovering, height }) { return (   <>     {hovering === true       ? <Tooltip id={this.props.id} />       : null}     <svg       className="Icon-svg Icon--hoverable-svg"       height={height}       viewBox="0 0 16 16" width="16">         <path d="M9 8a1 1 0 0 0-1-1H5.5a1 1 0 1 0 0 2H7v4a1 1 0 0 0 2 0zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm4 5.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />     </svg>   </> ) } 

في الواقع ، علينا الآن فقط تنفيذ مكون withHover . مما سبق ، يمكن فهم أنه يجب عليه القيام بثلاثة إجراءات:

  • خذ حجة إلى المكون.
  • إرجاع مكون جديد.
  • قم بعرض الوسيطة Component بتمرير خاصية hovering إليها.

▍ قبول حجة المكون


 function withHover (Component) { } 

▍إرجاع مكون جديد


 function withHover (Component) { return class WithHover extends React.Component { } } 

▍ عرض مكون المكون مع تمرير خاصية التحويم إليه


نواجه الآن السؤال التالي: كيفية الوصول إلى خاصية hovering ؟ في الواقع ، لقد كتبنا بالفعل رمز للعمل مع هذه الخاصية. نحتاج فقط إلى إضافته إلى المكون الجديد ، ثم تمرير خاصية hovering إليه عند عرض المكون الذي تم تمريره إلى المكون ذي الترتيب الأعلى في شكل الوسيطة Component .

 function withHover(Component) { return class WithHover extends React.Component {   state = { hovering: false }   mouseOver = () => this.setState({ hovering: true })   mouseOut = () => this.setState({ hovering: false })   render() {     return (       <div onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>         <Component hovering={this.state.hovering} />       </div>     );   } } } 

أفضل التحدث عن هذه الأشياء بالطريقة التالية (كما تقول وثائق التفاعل): المكون يحول الخصائص إلى واجهة مستخدم ، والمكون الأعلى رتبة يحول المكون إلى مكون آخر. في حالتنا ، سنقوم بتحويل مكونات DailyChart و DailyChart و DailyChart إلى مكونات جديدة ، بفضل خاصية hovering ، تعرف ما إذا كان مؤشر الماوس فوقها.

ملاحظات إضافية


في هذه المرحلة ، قمنا بمراجعة جميع المعلومات الأساسية حول مكونات النظام الأعلى. ومع ذلك ، هناك بعض الأشياء الأكثر أهمية للمناقشة.

إذا withHover نظرة على withHover ، فستلاحظ أن لديها نقطة ضعف واحدة على الأقل. هذا يعني أن مكون جهاز الاستقبال لخاصية hovering لن يواجه أي مشاكل مع هذه الخاصية. في معظم الحالات ، من المحتمل أن يكون هذا الافتراض مبررًا ، ولكن قد يحدث أن هذا غير مقبول. على سبيل المثال ، ماذا لو كان للمكون بالفعل خاصية hovering ؟ في هذه الحالة ، سيكون هناك تضارب في الأسماء. لذلك ، يمكن إجراء withHover على المكون withHover ، وهو السماح لمستخدم هذا المكون بتحديد الاسم الذي يجب أن تتحمله خاصية hovering تم تمريرها إلى المكونات. نظرًا لأن withHover هي مجرد وظيفة ، فلنقم بإعادة كتابتها بحيث withHover وسيطة ثانية تحدد اسم الخاصية ليتم تمريرها إلى المكون.

 function withHover(Component, propName = 'hovering') { return class WithHover extends React.Component {   state = { hovering: false }   mouseOver = () => this.setState({ hovering: true })   mouseOut = () => this.setState({ hovering: false })   render() {     const props = {       [propName]: this.state.hovering     }     return (       <div onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>         <Component {...props} />       </div>     );   } } } 

الآن ، وبفضل آلية المعلمة الافتراضية ES6 ، قمنا بتعيين القيمة القياسية للوسيطة الثانية على أنها hovering ، ولكن إذا أراد مستخدم المكون withHover تغيير هذا ، withHover تمرير الاسم ، الذي يحتاج إليه في هذه الوسيطة الثانية.

 function withHover(Component, propName = 'hovering') { return class WithHover extends React.Component {   state = { hovering: false }   mouseOver = () => this.setState({ hovering: true })   mouseOut = () => this.setState({ hovering: false })   render() {     const props = {       [propName]: this.state.hovering     }     return (       <div onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>         <Component {...props} />       </div>     );   } } } function Info ({ showTooltip, height }) { return (   <>     {showTooltip === true       ? <Tooltip id={this.props.id} />       : null}     <svg       className="Icon-svg Icon--hoverable-svg"       height={height}       viewBox="0 0 16 16" width="16">         <path d="M9 8a1 1 0 0 0-1-1H5.5a1 1 0 1 0 0 2H7v4a1 1 0 0 0 2 0zM4 0h8a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm4 5.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z" />     </svg>   </> ) } const InfoWithHover = withHover(Info, 'showTooltip') 

مشكلة في تنفيذ التمرير


ربما لاحظت مشكلة أخرى في تنفيذ withHover . إذا قمنا بتحليل مكون Info بنا ، ستلاحظ أنه ، من بين أمور أخرى ، يقبل خاصية height . الطريقة التي رتبنا بها كل شيء الآن تعني أنه سيتم تعيين height إلى undefined . والسبب في ذلك هو أن المكون withHover هو المكون المسؤول عن عرض ما يتم تمريره إليه كوسيطة Component . الآن نحن لا ننقل أي خصائص بخلاف hovering الذي hovering لمكون المكون.

 const InfoWithHover = withHover(Info) ... return <InfoWithHover height="16px" /> 

يتم تمرير خاصية height إلى مكون InfoWithHover . وما هذا المكون؟ هذا هو العنصر الذي نعود منه مع withHover .

 function withHover(Component, propName = 'hovering') { return class WithHover extends React.Component {   state = { hovering: false }   mouseOver = () => this.setState({ hovering: true })   mouseOut = () => this.setState({ hovering: false })   render() {     console.log(this.props) // { height: "16px" }     const props = {       [propName]: this.state.hovering     }     return (       <div onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>         <Component {...props} />       </div>     );   } } } 

داخل مكون WithHover this.props.height ، ولكن في المستقبل لن نقوم بأي شيء مع هذه الخاصية. نحتاج إلى تمرير هذه الخاصية إلى الوسيطة Component ، التي نقدمها.

 render() {     const props = {       [propName]: this.state.hovering,       ...this.props,     }     return (       <div onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>         <Component {...props} />       </div>     ); } 

حول مشاكل العمل مع مكونات الطرف الثالث من أعلى مرتبة


نحن نعتقد أنك قدرت بالفعل مزايا استخدام مكونات عالية الترتيب في إعادة استخدام المنطق في مكونات مختلفة دون الحاجة إلى نسخ نفس الرمز. الآن دعونا نسأل أنفسنا إذا كانت هناك أي عيوب في مكونات النظام الأعلى. يمكن الإجابة على هذا السؤال بشكل إيجابي ، وقد التقينا بالفعل بهذه العيوب.

عند استخدام HOC ، يحدث انقلاب التحكم . تخيل أننا نستخدم مكونًا عالي الترتيب لم نقم بتطويره ، مثل withRouter Router. وفقًا للوثائق ، withRouter match location history إلى المكون الذي لفه عند عرضه.

 class Game extends React.Component { render() {   const { match, location, history } = this.props // From React Router   ... } } export default withRouter(Game) 

يرجى ملاحظة أننا لا ننشئ عنصر Game (أي - <Game /> ). نحن ننقل بالكامل مكون React Router ونثق في هذا المكون ليس فقط للعرض ، ولكن أيضًا لتمرير الخصائص الصحيحة إلى المكون الخاص بنا. لقد واجهنا بالفعل هذه المشكلة من قبل عندما تحدثنا عن تعارض محتمل في الاسم عند تمرير خاصية hovering . ولإصلاح ذلك ، قررنا السماح withHover باستخدام الوسيطة الثانية لتكوين اسم الخاصية المقابلة. باستخدام withRouter لشخص آخر مع جهاز withRouter ليس لدينا مثل هذه الفرصة. إذا تم استخدام خصائص match أو location أو history بالفعل في مكون Game ، فيمكننا القول أننا لم نعد محظوظين. وبالتحديد ، يتعين علينا إما تغيير هذه الأسماء في المكون الخاص بنا ، أو رفض استخدام withRouter .

الملخص


بالحديث عن HOC في React ، هناك شيئان مهمان يجب مراعاتهما. بادئ ذي بدء ، HOC هو مجرد نمط. لا يمكن حتى تسمية المكونات الأعلى بشيء خاص بـ React ، على الرغم من حقيقة أنها مرتبطة ببنية التطبيق. ثانيًا ، لتطوير تطبيقات React ، لا تحتاج إلى معرفة مكونات النظام الأعلى. قد تكون غير مألوف بالنسبة لهم ، لكن اكتب برامج ممتازة. ومع ذلك ، كما هو الحال في أي عمل تجاري ، كلما كان لديك المزيد من الأدوات ، كلما كانت نتيجة عملك أفضل. وإذا قمت بكتابة تطبيقات باستخدام React ، فسوف تضر نفسك دون إضافة HOC إلى ترسانتك.

أعزائي القراء! هل تستخدم مكونات النظام الأعلى في React؟

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


All Articles