نقدم انتباهكم إلى ترجمة لمقال سكوت دوميس ، الذي نشر على blog.bitsrc.io. اكتشف كيف أن المكونات يجب أن تكون صغيرة قدر الإمكان وكيف يؤثر مبدأ المسؤولية الفردية على جودة التطبيقات.

صور
أوستن كيرك مع
Unsplashتتمثل ميزة نظام React Component (والمكتبات المشابهة) في تقسيم واجهة المستخدم الخاصة بك إلى أجزاء صغيرة يسهل قراءتها وإعادة استخدامها.
هذه المكونات مدمجة (100-200 سطر) ، والتي تتيح للمطورين الآخرين فهمها وتعديلها بسهولة.
على الرغم من أن المكونات ، كقاعدة عامة ، تحاول أن تكون أقصر ، لا يوجد قيود واضحة وصارمة على طولها. لن تمانع React إذا قررت أن تلائم طلبك في مكون واحد ضخم ومخيف ، يتكون من 3000 سطر.
... ولكن هذا لا يستحق كل هذا العناء. معظم مكوناتك ، على الأرجح ، ضخمة بالفعل - أو بالأحرى ، فهي تؤدي وظائف كثيرة للغاية.
في هذه المقالة ، سأثبت أن معظم المكونات (حتى مع طول 200 سطر المعتاد) يجب أن تكون أكثر استهدافًا بدقة. يجب أن تؤدي وظيفة واحدة فقط ، وأداء ذلك جيدا. هذا ما يقوله إدي عثماني عظيم
هنا .
نصيحة : عند العمل في JS ،
استخدم Bit لتنظيم المكونات وتجميعها وإعادة استخدامها كأجزاء قديمة. تعتبر Bit أداة فعالة للغاية لهذا العمل ، وسوف تساعدك أنت وفريقك على توفير الوقت وتسريع عملية التجميع. مجرد محاولة إعطائها.
دعونا نوضح كيف ، عند إنشاء المكونات
، قد يحدث خطأ ما .
لدينا التطبيق
تخيل أن لدينا تطبيقًا قياسيًا للمدونين. وهنا ما على الشاشة الرئيسية:
class Main extends React.Component { render() { return ( <div> <header> // Header JSX </header> <aside id="header"> // Sidebar JSX </aside> <div id="post-container"> {this.state.posts.map(post => { return ( <div className="post"> // Post JSX </div> ); })} </div> </div> ); } }
(يجب اعتبار هذا المثال ، مثل العديد من الأمثلة اللاحقة ، رمزًا زائفًا.)يعرض اللوحة العلوية والشريط الجانبي وقائمة المنشورات. كل شيء بسيط.
نظرًا لأننا نحتاج أيضًا إلى تنزيل المنشورات ، يمكننا القيام بذلك أثناء تثبيت المكون:
class Main extends React.Component { state = { posts: [] }; componentDidMount() { this.loadPosts(); } loadPosts() {
لدينا أيضا بعض المنطق الذي يسمى الشريط الجانبي. إذا نقر المستخدم على الزر في اللوحة العلوية ، فسيخرج الجانب. يمكنك إغلاقها من الأعلى ومن اللوحة الجانبية نفسها.
class Main extends React.Component { state = { posts: [], isSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
أصبح مكوننا أكثر تعقيدًا بعض الشيء ، ولكن لا يزال من السهل قراءته.
يمكن القول أن جميع أجزائه تخدم غرضًا واحدًا: عرض الصفحة الرئيسية للتطبيق. لذلك نحن نتبع مبدأ المسؤولية وحدها.
ينص مبدأ المسؤولية الفردية على أن المكون الواحد يجب أن يؤدي وظيفة واحدة فقط. إذا أعدنا صياغة التعريف المأخوذ من
wikipedia.org ، اتضح أن كل مكون يجب أن يكون مسؤولاً عن جزء واحد فقط من الوظيفة [التطبيق].
المكون الرئيسي لدينا يلبي هذا المطلب. ما هي المشكلة؟
فيما يلي صيغة مختلفة للمبدأ:
يجب أن يكون لأي [مكون] سبب واحد فقط للتغيير .
هذا التعريف مأخوذ من
كتاب روبرت مارتن
، Rapid Software Development. المبادئ ، الأمثلة ، الممارسة ، وهي ذات أهمية كبيرة.
من خلال التركيز على
سبب واحد لتغيير مكوناتنا ، يمكننا إنشاء تطبيقات أفضل يسهل تكوينها.
من أجل الوضوح ، دعنا نعقد مكوننا.
تعقيد
افترض أنه بعد شهر من تنفيذ المكون الرئيسي ، تم تعيين ميزة جديدة للمطور من فريقنا. سيتمكن المستخدم الآن من إخفاء منشور (على سبيل المثال ، إذا كان يحتوي على محتوى غير لائق).
هذا ليس من الصعب القيام به!
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [] };
زميلنا تعامل بسهولة مع هذا. لقد أضافت طريقة واحدة جديدة وخاصية جديدة واحدة. لم يكن لدى أي من أولئك الذين نظروا في قائمة التغييرات القصيرة أي اعتراضات.
بعد أسبوعين ، تم الإعلان عن ميزة أخرى - شريط جانبي محسّن لإصدار الهاتف المحمول. بدلاً من العبث باستخدام CSS ، يقرر المطور إنشاء العديد من مكونات JSX التي سيتم تشغيلها فقط على الأجهزة المحمولة.
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false };
تغيير صغير آخر. زوجان من الأساليب الجديدة المعروفة وخاصية جديدة.
وهنا لدينا مشكلة. لا يزال
Main
يؤدي وظيفة واحدة فقط (تقديم الشاشة الرئيسية) ، لكنك تنظر في جميع هذه الطرق التي نتعامل معها الآن:
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
يصبح مكوننا كبيرًا وضخمًا ، ومن الصعب فهمه. ومع توسع الوظائف ، سوف يزداد الوضع سوءًا.
ما الخطأ الذي حدث؟
السبب الوحيد
دعنا نعود إلى تعريف مبدأ المسؤولية الفردية:
يجب أن يكون لأي مكون سبب واحد فقط للتغيير .
في السابق ، قمنا بتغيير طريقة عرض المنشورات ، لذلك كان علينا تغيير المكون الرئيسي لدينا. بعد ذلك ، قمنا بتغيير طريقة فتح الشريط الجانبي - ومرة أخرى قمنا بتغيير المكون الرئيسي.
يحتوي هذا المكون على العديد من الأسباب غير المرتبطة للتغيير.
هذا يعني أنه يؤدي الكثير من الوظائف .
بمعنى آخر ، إذا كان يمكنك تغيير جزء من المكون الخاص بك بشكل كبير وهذا لا يؤدي إلى تغييرات في جزء آخر منه ، فإن المكون الخاص بك يتحمل الكثير من المسؤولية.
فصل أكثر كفاءة
الحل بسيط: تحتاج إلى تقسيم المكون الرئيسي إلى عدة أجزاء. كيف نفعل ذلك؟
لنبدأ من جديد. يبقى عرض الشاشة الرئيسية من مسؤولية المكون الرئيسي ، لكننا نقوم بتقليله فقط لعرض المكونات ذات الصلة:
class Main extends React.Component { render() { return ( <Layout> <PostList /> </Layout> ); } }
عظيم
إذا غيرنا فجأة تخطيط الشاشة الرئيسية (على سبيل المثال ، أضف أقسامًا إضافية) ، فسيتم تغيير Main أيضًا. في حالات أخرى ، لن يكون لدينا أي سبب للمسه. عظيم
دعنا ننتقل إلى
Layout
:
class Layout extends React.Component { render() { return ( <SidebarDisplay> {(isSidebarOpen, toggleSidebar) => ( <div> <Header openSidebar={toggleSidebar} /> <Sidebar isOpen={isSidebarOpen} close={toggleSidebar} /> </div> )} </SidebarDisplay> ); } }
هذا هو أكثر تعقيدا قليلا.
Layout
هو المسؤول عن تقديم مكونات التخطيط (اللوحة الجانبية / اللوحة العلوية). لكننا لن نستسلم للإغراء ونمنح
Layout
مسؤولية تحديد ما إذا كان الشريط الجانبي مفتوحًا أم لا.
نقوم بتعيين هذه الوظيفة إلى مكون
SidebarDisplay
، والذي يمرر الطرق أو الحالة الضرورية إلى مكونات
SidebarDisplay
Sidebar
.
(المثال أعلاه هو مثال لنموذج Render Props عبر الأطفال في React. إذا لم تكن معتادًا عليه ، فلا تقلق. من المهم وجود عنصر منفصل يتحكم في حالة الفتح / الإغلاق للشريط الجانبي.)وبعد ذلك ، يمكن أن يكون
Sidebar
نفسه بسيطًا تمامًا إذا كان مسؤولًا فقط عن عرض الشريط الجانبي على اليمين.
class Sidebar extends React.Component { isMobile() {
مرة أخرى ، نقاوم إغراء إدراج JSX لأجهزة الكمبيوتر / الأجهزة المحمولة مباشرةً في هذا المكون ، لأنه في هذه الحالة سيكون هناك سببان للتغيير.
دعنا ننظر إلى مكون آخر:
class PostList extends React.Component { state = { postsToHide: [] } filterPosts(posts) {
PostList
فقط إذا قمنا بتغيير طريقة عرض قائمة
PostList
. يبدو واضحا ، أليس كذلك؟ هذا هو بالضبط ما نحتاجه.
PostLoader
يتغير فقط إذا قمنا بتغيير طريقة تحميل
PostLoader
. وأخيرًا ، لا يتغير
Post
إلا إذا قمنا بتغيير طريقة عرض المنشور.
الخاتمة
كل هذه المكونات صغيرة وتؤدي وظيفة صغيرة واحدة. من السهل تحديد أسباب التغييرات فيها ، ويتم اختبار المكونات نفسها وتصحيحها.
الآن أصبح تطبيقنا أسهل في التعديل - إعادة ترتيب المكونات وإضافة وظائف جديدة وتوسيع نطاقها. تحتاج فقط إلى إلقاء نظرة على ملف مكون لتحديد
ما هو عليه.
نحن نعلم أن مكوناتنا ستتغير وتنمو بمرور الوقت ، ولكن تطبيق هذه القاعدة العالمية سيساعدك على تجنب الديون الفنية وزيادة سرعة الفريق. كيفية توزيع المكونات متروك لك ، ولكن تذكر -
يجب أن يكون هناك سبب واحد فقط لتغيير المكون .
شكرا لاهتمامكم ونتطلع إلى تعليقاتكم!