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

في هذا الجزء من ترجمة البرنامج التعليمي React ، سنتحدث عن بنية تطبيقات React. على وجه الخصوص ، سنناقش نمط الحاوية / المكونات الشائعة.

صورة

الجزء 1: نظرة عامة على الدورة ، وأسباب شعبية React ، ReactDOM و JSX
الجزء 2: المكونات الوظيفية
الجزء 3: ملفات المكونات ، هيكل المشروع
الجزء 4: مكونات الوالدين والطفل
الجزء 5: بدء العمل في تطبيق TODO ، أساسيات التصميم
الجزء 6: حول بعض ميزات الدورة ، JSX وجافا سكريبت
الجزء 7: الأنماط المضمنة
الجزء 8: مواصلة العمل على تطبيق TODO ، الإلمام بخصائص المكونات
الجزء 9: خصائص المكون
الجزء 10: ورشة عمل حول العمل مع خصائص المكون والتصميم
الجزء 11: توليد العلامات الديناميكية وطريقة صفائف الخريطة
الجزء 12: ورشة العمل ، المرحلة الثالثة من العمل على طلب TODO
الجزء 13: المكونات القائمة على الفصل
الجزء 14: ورشة عمل حول المكونات القائمة على الفصل ، وحالة المكون
الجزء 15: ورش العمل الصحية المكونة
الجزء 16: المرحلة الرابعة من العمل على طلب TODO ، التعامل مع الأحداث
الجزء 17: المرحلة الخامسة من العمل على تطبيق TODO ، وتعديل حالة المكونات
الجزء 18: المرحلة السادسة من العمل على طلب TODO
الجزء 19: طرق دورة حياة المكون
الجزء 20: الدرس الأول في التقديم الشرطي
الجزء 21: الدرس الثاني وورشة العمل حول التقديم الشرطي
الجزء 22: المرحلة السابعة من العمل على تطبيق TODO ، وتنزيل البيانات من مصادر خارجية
الجزء 23: الدرس الأول حول العمل مع النماذج
الجزء 24: نماذج الدرس الثاني
الجزء 25: ورشة عمل حول العمل مع النماذج
الجزء 26: بنية التطبيق ، نمط الحاوية / المكون
الجزء 27: مشروع المقرر

الدرس 44. هندسة التطبيق ، نمط الحاوية / المكون


الأصل

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

في الدرس العملي السابق ، أنشأنا مكونًا ضخمًا يصل طول رمزه إلى 150 سطرًا. إليك الكود الذي حصلنا عليه بعد ذلك:

import React, {Component} from "react" class App extends Component {    constructor() {        super()        this.state = {            firstName: "",            lastName: "",            age: "",            gender: "",            destination: "",            isVegan: false,            isKosher: false,            isLactoseFree: false        }        this.handleChange = this.handleChange.bind(this)    }       handleChange(event) {        const {name, value, type, checked} = event.target        type === "checkbox" ?            this.setState({                [name]: checked            })        :        this.setState({            [name]: value        })    }       render() {        return (            <main>                <form>                    <input                        name="firstName"                        value={this.state.firstName}                        onChange={this.handleChange}                        placeholder="First Name"                    />                    <br />                                       <input                        name="lastName"                        value={this.state.lastName}                        onChange={this.handleChange}                        placeholder="Last Name"                    />                    <br />                                       <input                        name="age"                        value={this.state.age}                        onChange={this.handleChange}                        placeholder="Age"                    />                    <br />                                       <label>                        <input                            type="radio"                            name="gender"                            value="male"                            checked={this.state.gender === "male"}                            onChange={this.handleChange}                        /> Male                    </label>                                       <br />                                       <label>                        <input                            type="radio"                            name="gender"                            value="female"                            checked={this.state.gender === "female"}                            onChange={this.handleChange}                        /> Female                    </label>                                       <br />                                       <select                        value={this.state.destination}                        name="destination"                        onChange={this.handleChange}                    >                        <option value="">-- Please Choose a destination --</option>                        <option value="germany">Germany</option>                        <option value="norway">Norway</option>                        <option value="north pole">North Pole</option>                        <option value="south pole">South Pole</option>                    </select>                                       <br />                                       <label>                        <input                            type="checkbox"                            name="isVegan"                            onChange={this.handleChange}                            checked={this.state.isVegan}                        /> Vegan?                    </label>                    <br />                                       <label>                        <input                            type="checkbox"                            name="isKosher"                            onChange={this.handleChange}                            checked={this.state.isKosher}                        /> Kosher?                    </label>                    <br />                                       <label>                        <input                            type="checkbox"                            name="isLactoseFree"                            onChange={this.handleChange}                            checked={this.state.isLactoseFree}                        /> Lactose Free?                    </label>                    <br />                                       <button>Submit</button>                </form>                <hr />                <h2><font color="#3AC1EF">Entered information:</font></h2>                <p>Your name: {this.state.firstName} {this.state.lastName}</p>                <p>Your age: {this.state.age}</p>                <p>Your gender: {this.state.gender}</p>                <p>Your destination: {this.state.destination}</p>                <p>Your dietary restrictions:</p>                               <p>Vegan: {this.state.isVegan ? "Yes" : "No"}</p>                <p>Kosher: {this.state.isKosher ? "Yes" : "No"}</p>                <p>Lactose Free: {this.state.isLactoseFree ? "Yes" : "No"}</p>                           </main>        )    } } export default App 

العيب الأول لهذا الكود ، الذي يلفت انتباهك على الفور ، هو أنه عند العمل بها ، عليك دائمًا التمرير في نافذة المحرر.

يمكنك ملاحظة أن الجزء الأكبر من هذا الرمز هو منطق تشكيل واجهة التطبيق ، ومحتويات طريقة التقديم render() . بالإضافة إلى ذلك ، هناك قدر معين من التعليمات البرمجية مسؤول عن تهيئة حالة المكون. يحتوي المكون أيضًا على ما يسمى "منطق العمل" (أي ، ما ينفذ منطق أداء التطبيق). هذا هو رمز الأسلوب handleChange() .

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

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

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

هنا مادة دان أبراموف التي يستكشف فيها هذه الفكرة.

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

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

 import React, {Component} from "react" import Form from "./Form" function App() {   return (       <Form />   ) } export default App 

إليك ما يعرضه التطبيق على الشاشة في هذه المرحلة من العمل.


تطبيق في المتصفح

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

لقد قمنا بتحسين بنية التطبيق بشكل طفيف ، لكن المشكلة الرئيسية ، المعبر عنها في حقيقة أن أحد المكونات يتحمل مسؤولية كبيرة ، لم يتم حلها بعد. لقد نقلنا ببساطة كل ما كان في وقت سابق في مكون App إلى مكون Form . لذلك ، نحن الآن بصدد حل هذه المشكلة. للقيام بذلك ، قم بإنشاء ملف آخر - FormComponent.js في نفس المجلد الذي Form.js App.js ملفات App.js و App.js سيمثل هذا الملف مكون العرض التقديمي المسؤول عن رؤية النموذج. في الواقع ، يمكنك تسميتها بشكل مختلف ، يمكنك هيكلة ملفات المكونات بشكل مختلف ، كل هذا يتوقف على احتياجات وحجم مشروع معين. Form.js الملف Form.js على منطق النموذج ، أي رمز مكون الحاوية. لذلك ، قم بإعادة تسميته إلى FormContainer.js وقم بتغيير أمر الاستيراد في رمز مكون App ، مع إحضاره إلى هذا النموذج:

 import Form from "./FormContainer" 

يمكنك أيضًا إعادة تسمية مكون Form إلى FormContainer ، لكننا لن نفعل ذلك. سنقوم الآن بنقل الكود المسؤول عن تقديم النموذج من ملف FormContainer.js إلى ملف FormComponent.js .

المكون FormComponent سيكون وظيفي. إليكم كيف سيبدو رمزه في هذه المرحلة من العمل:

 function FormComponent(props) {   return (       <main>           <form>               <input                   name="firstName"                   value={this.state.firstName}                   onChange={this.handleChange}                   placeholder="First Name"               />               <br />                             <input                   name="lastName"                   value={this.state.lastName}                   onChange={this.handleChange}                   placeholder="Last Name"               />               <br />                             <input                   name="age"                   value={this.state.age}                   onChange={this.handleChange}                   placeholder="Age"               />               <br />                             <label>                   <input                       type="radio"                       name="gender"                       value="male"                       checked={this.state.gender === "male"}                       onChange={this.handleChange}                   /> Male               </label>                             <br />                             <label>                   <input                       type="radio"                       name="gender"                       value="female"                       checked={this.state.gender === "female"}                       onChange={this.handleChange}                   /> Female               </label>                             <br />                             <select                   value={this.state.destination}                   name="destination"                   onChange={this.handleChange}               >                   <option value="">-- Please Choose a destination --</option>                   <option value="germany">Germany</option>                   <option value="norway">Norway</option>                   <option value="north pole">North Pole</option>                   <option value="south pole">South Pole</option>               </select>                             <br />                             <label>                   <input                       type="checkbox"                       name="isVegan"                       onChange={this.handleChange}                       checked={this.state.isVegan}                   /> Vegan?               </label>               <br />                             <label>                   <input                       type="checkbox"                       name="isKosher"                       onChange={this.handleChange}                       checked={this.state.isKosher}                   /> Kosher?               </label>               <br />                             <label>                   <input                       type="checkbox"                       name="isLactoseFree"                       onChange={this.handleChange}                       checked={this.state.isLactoseFree}                   /> Lactose Free?               </label>               <br />                             <button>Submit</button>           </form>           <hr />           <h2><font color="#3AC1EF">Entered information:</font></h2>           <p>Your name: {this.state.firstName} {this.state.lastName}</p>           <p>Your age: {this.state.age}</p>           <p>Your gender: {this.state.gender}</p>           <p>Your destination: {this.state.destination}</p>           <p>Your dietary restrictions:</p>                     <p>Vegan: {this.state.isVegan ? "Yes" : "No"}</p>           <p>Kosher: {this.state.isKosher ? "Yes" : "No"}</p>           <p>Lactose Free: {this.state.isLactoseFree ? "Yes" : "No"}</p>                 </main>   ) } 

إذا نظرت إلى هذا الرمز ، يصبح من الواضح أننا لا نستطيع أن نقصر أنفسنا على مجرد نقله من ملف إلى آخر ، لأن هناك الآن روابط للحالة (على سبيل المثال ، this.state.firstName ) ومعالج الأحداث ( this.handleChange ) ، الذي كان في نفس المكون استنادًا إلى الفئة التي كانت بها شفرة العرض هذه. الآن ، سيتم أخذ كل ما تم نقله مسبقًا من نفس الفئة التي يوجد بها رمز العرض من الخصائص التي تم تمريرها إلى المكون. هناك بعض المشاكل الأخرى. سنقوم الآن بإصلاح هذا الرمز ، لكن أولاً سنعود إلى رمز مكون Form ، والذي يوجد الآن في ملف FormContainer.js .

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

 import React, {Component} from "react" import FormComponent from "./FormComponent" class Form extends Component {   constructor() {       super()       this.state = {           firstName: "",           lastName: "",           age: "",           gender: "",           destination: "",           isVegan: false,           isKosher: false,           isLactoseFree: false       }       this.handleChange = this.handleChange.bind(this)   }     handleChange(event) {       const {name, value, type, checked} = event.target       type === "checkbox" ?           this.setState({               [name]: checked           })       :       this.setState({           [name]: value       })   }     render() {       return(           <FormComponent               handleChange={this.handleChange}               data={this.state}           />       )   } } export default Form 

سنقوم FormComponent رمز مكون FormComponent ، FormComponent إلى النموذج التالي:

 import React from "react" function FormComponent(props) {   return (       <main>           <form>               <input                   name="firstName"                   value={props.data.firstName}                   onChange={props.handleChange}                   placeholder="First Name"               />               <br />                             <input                   name="lastName"                   value={props.data.lastName}                   onChange={props.handleChange}                   placeholder="Last Name"               />               <br />                             <input                   name="age"                   value={props.data.age}                   onChange={props.handleChange}                   placeholder="Age"               />               <br />                             <label>                   <input                       type="radio"                       name="gender"                       value="male"                       checked={props.data.gender === "male"}                       onChange={props.handleChange}                   /> Male               </label>                             <br />                             <label>                   <input                       type="radio"                       name="gender"                       value="female"                       checked={props.data.gender === "female"}                       onChange={props.handleChange}                   /> Female               </label>                             <br />                             <select                   value={props.data.destination}                   name="destination"                   onChange={props.handleChange}               >                   <option value="">-- Please Choose a destination --</option>                   <option value="germany">Germany</option>                   <option value="norway">Norway</option>                   <option value="north pole">North Pole</option>                   <option value="south pole">South Pole</option>               </select>                             <br />                             <label>                   <input                       type="checkbox"                       name="isVegan"                       onChange={props.handleChange}                       checked={props.data.isVegan}                   /> Vegan?               </label>               <br />                             <label>                   <input                       type="checkbox"                       name="isKosher"                       onChange={props.handleChange}                       checked={props.data.isKosher}                   /> Kosher?               </label>               <br />                             <label>                   <input                       type="checkbox"                       name="isLactoseFree"                       onChange={props.handleChange}                       checked={props.data.isLactoseFree}                   /> Lactose Free?               </label>               <br />                             <button>Submit</button>           </form>           <hr />           <h2><font color="#3AC1EF">Entered information:</font></h2>           <p>Your name: {props.data.firstName} {props.data.lastName}</p>           <p>Your age: {props.data.age}</p>           <p>Your gender: {props.data.gender}</p>           <p>Your destination: {props.data.destination}</p>           <p>Your dietary restrictions:</p>                     <p>Vegan: {props.data.isVegan ? "Yes" : "No"}</p>           <p>Kosher: {props.data.isKosher ? "Yes" : "No"}</p>           <p>Lactose Free: {props.data.isLactoseFree ? "Yes" : "No"}</p>                 </main>   ) } export default FormComponent 

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

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

نتيجة لذلك ، حققنا فصل المسؤوليات بين المكونات. مكون Form من ملف FormContainer.js الآن مشغول بشكل خاص بواسطة منطق التطبيق ، بينما FormComponent مكون FormComponent من ملف FormComponent.js فقط على التعليمات البرمجية التي تشكل واجهة التطبيق. مكون App الآن مسؤول فقط عن تجميع الصفحة من كتل كبيرة.

تجدر الإشارة إلى أنه نظرًا لوجود مكتبات مثل Redux و Context API التي تم إصدارها مؤخرًا ، لم يعد نمط الحاوية / المكون الذي تمت مناقشته هنا مناسبًا كما كان من قبل. على سبيل المثال ، يمكن لـ Redux دعم الحالة العامة للتطبيق الذي يمكن أن تستخدمه المكونات.

النتائج


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

أعزائي القراء! ما أنماط التصميم التي تستخدمها عند تطوير تطبيقات React؟

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


All Articles