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

تقدم المادة ، الجزء الأول من الترجمة التي ننشرها اليوم ، نصائح لكتابة تعليمات برمجية نظيفة لتطبيقات React. أهمية هذه النصائح هي الأعلى ، وكلما زاد حجم المشروع الذي يتم فيه تطبيق المبادئ المنصوص عليها فيها. في المشروعات الصغيرة ، ربما يمكنك القيام بذلك دون تطبيق هذه المبادئ. عند تحديد ما هو مطلوب في كل موقف معين ، يجدر الاسترشاد بالحس السليم.
1. تدمير الخصائص
تعد خصائص التدمير (في مصطلحات React English يطلق عليها "الدعائم") طريقة جيدة لجعل الشفرة أكثر نظافة وتحسين قدرات الدعم. والحقيقة هي أن هذا يسمح لك بالتعبير بوضوح أو إعلان ما يستخدمه الكيان (مثل مكون React). ومع ذلك ، لا يجبر هذا الأسلوب المطورين على القراءة في تنفيذ المكون لمعرفة تكوين الخصائص المرتبطة به.
تتيح خصائص التدمير أيضًا للمبرمج تعيين قيمه الافتراضية. هذا شائع جدا:
import React from 'react' import Button from 'components/Button' const MyComponent = ({ placeholder = '', style, ...otherProps }) => { return ( <Button type="button" style={{ border: `1px solid ${placeholder ? 'salmon' : '#333'}`, ...style, }} {...otherProps} > Click Me </Button> ) } export default MyComponent
واحدة من أكثر النتائج اللطيفة لاستخدام التدمير في JavaScript ، والتي تمكنت من العثور عليها ، أنها تتيح لك دعم خيارات متنوعة للمعلمات.
على سبيل المثال ، لدينا وظيفة
authenticate
، والتي اتخذت كمعلمة
token
المستخدم لمصادقة المستخدمين. في وقت لاحق ، كان من الضروري جعله يقبل الكيان
jwt_token
. سبب هذه الحاجة هو تغيير في بنية استجابة الخادم. بفضل استخدام التدمير ، يمكن بسهولة تنظيم الدعم لكلا المعلمتين دون الحاجة إلى تغيير معظم كود الوظيفة:
سيتم تقييم
jwt_token
عندما يصل
token
إلى
token
. نتيجة لذلك ، إذا تبين أن
jwt_token
رمز مميز صالح ، وكان الكيان
token
undefined
، فسوف تقع قيمة
jwt_token
في
token
. إذا كان في
token
بالفعل بعض القيمة التي لم تكن خاطئة بواسطة قواعد JS (أي ، بعض الرموز الحقيقية) ، فعندها سيكون
token
ما هو موجود بالفعل.
2. ضع ملفات المكونات في هيكل مجلد مدروس جيدًا
ألقِ نظرة على بنية الدليل التالية:
- SRC
- المكونات
- Breadcrumb.js
- CollapsedSeparator.js
- مساهمة
- index.js
- Input.js
- utils.js
- focusManager.js
- بطاقة
- index.js
- Card.js
- CardDivider.js
- Button.js
- Typography.js
قد تشمل فتات الخبز فواصل. يتم استيراد مكون
CollapsedSeparator
في ملف
Breadcrumb.js
. هذا يعطينا معرفة أنه في تنفيذ المشروع المعني ترتبط. ومع ذلك ، قد يشير شخص لا يمتلك هذه المعلومات إلى أن
Breadcrumb
و
CollapsedSeparator
هما زوجان من المكونات المستقلة تمامًا والتي لا ترتبط ببعضها البعض بأي طريقة. خاصة - إذا
CollapsedSeparator
يكن
CollapsedSeparator
أي علامات واضحة على أن هذا المكون يرتبط بمكون
Breadcrumb
. من بين هذه العلامات ، على سبيل المثال ، قد يكون هناك بادئة
Breadcrumb
، تستخدم في اسم المكون ، والتي يمكن أن تحول الاسم إلى شيء مثل
BreadcrumbCollapsedSeparator.js
.
نظرًا لأننا نعرف أن
Breadcrumb
و
CollapsedSeparator
Breadcrumb
ببعضهما البعض ، فقد نتساءل عن سبب عدم وضعهما في مجلد منفصل ، مثل
Input
Card
. عند القيام بذلك ، يمكننا أن نبدأ في وضع افتراضات مختلفة حول سبب وجود مواد مثل هذا المشروع في مواد المشروع. قل ، هنا يمكنك التفكير في المكونات التي تم وضعها على المستوى الأعلى من المشروع لمساعدتهم في العثور على هذه المكونات بسرعة ، مع الاهتمام بأولئك الذين سيعملون مع المشروع. نتيجة لذلك ، تبدو العلاقة بين أجزاء المشروع غامضة إلى حد ما بالنسبة للمطور الجديد. يجب أن يكون لاستخدام أساليب كتابة التعليمات البرمجية النظيفة تأثير معاكس تمامًا. النقطة المهمة هي أنه بفضلهم ، يحصل المطور الجديد على فرصة لقراءة رمز شخص آخر وفهم جوهر الموقف على الفور.
إذا استخدمنا بنية دليل مدروسة في مثالنا ، فسنحصل على شيء مثل التالي:
- SRC
- التفصيلي
- index.js
- Breadcrumb.js
- CollapsedSeparator.js
- مساهمة
- index.js
- Input.js
- utils.js
- focusManager.js
- بطاقة
- index.js
- Card.js
- CardDivider.js
- Button.js
- Typography.js
الآن لا يهم عدد المكونات المرتبطة بمكون
Breadcrumb
سيتم إنشاؤه. طالما توجد ملفاتهم في نفس الدليل مثل
Breadcrumb.js
، فسوف نعرف أنها مرتبطة بمكون
Breadcrumb
:
- SRC
- التفصيلي
- index.js
- Breadcrumb.js
- CollapsedSeparator.js
- Expander.js
- BreadcrumbText.js
- BreadcrumbHotdog.js
- BreadcrumbFishes.js
- BreadcrumbLeftOvers.js
- BreadcrumbHead.js
- BreadcrumbAddict.js
- BreadcrumbDragon0814.js
- BreadcrumbContext.js
- مساهمة
- index.js
- Input.js
- utils.js
- focusManager.js
- بطاقة
- index.js
- Card.js
- CardDivider.js
- Button.js
- Typography.js
هذه هي الطريقة التي يظهر بها العمل في الهياكل المماثلة في الكود:
import React from 'react' import Breadcrumb, { CollapsedSeparator, Expander, BreadcrumbText, BreadcrumbHotdog, BreadcrumbFishes, BreadcrumbLeftOvers, BreadcrumbHead, BreadcrumbAddict, BreadcrumbDragon0814, } from '../../../../../../../../../../components/Breadcrumb' const withBreadcrumbHotdog = (WrappedComponent) => (props) => ( <WrappedComponent BreadcrumbHotdog={BreadcrumbHotdog} {...props} /> ) const WorldOfBreadcrumbs = ({ BreadcrumbHotdog: BreadcrumbHotdogComponent, }) => { const [hasFishes, setHasFishes] = React.useState(false) return ( <BreadcrumbDragon0814 hasFishes={hasFishes} render={(results) => ( <BreadcrumbFishes> {({ breadcrumbFishes }) => ( <BreadcrumbLeftOvers.Provider> <BreadcrumbHotdogComponent> <Expander> <BreadcrumbText> <BreadcrumbAddict> <pre> <code>{JSON.stringify(results, null, 2)}</code> </pre> </BreadcrumbAddict> </BreadcrumbText> </Expander> {hasFishes ? breadcrumbFishes.map((fish) => ( <> {fish} <CollapsedSeparator /> </> )) : null} </BreadcrumbHotdogComponent> </BreadcrumbLeftOvers.Provider> )} </BreadcrumbFishes> )} /> ) } export default withBreadcrumbHotdog(WorldOfBreadcrumbs)
3. اسم المكونات باستخدام اصطلاحات التسمية القياسية
باستخدام معايير معينة عندما تسهل مكونات التسمية على شخص ليس مؤلف المشروع قراءة التعليمات البرمجية لهذا المشروع.
على سبيل المثال ، عادة ما تكون بادئة أسماء
مكونات الترتيب العالي (HOCs). يتم استخدام العديد من المطورين لأسماء المكونات هذه:
import React from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' import getDisplayName from 'utils/getDisplayName' const withFreeMoney = (WrappedComponent) => { class WithFreeMoney extends React.Component { giveFreeMoney() { return 50000 } render() { return ( <WrappedComponent additionalMoney={[ this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), ]} {...this.props} /> ) } } WithFreeMoney.displayName = `withFreeMoney(${getDisplayName( WrappedComponent, )}$)` hoistNonReactStatics(WithFreeMoney, WrappedComponent) return WithFreeMoney } export default withFreeMoney
لنفترض أن شخصًا ما قرر التراجع عن هذه الممارسة وعمل ذلك:
import React from 'react' import hoistNonReactStatics from 'hoist-non-react-statics' import getDisplayName from 'utils/getDisplayName' const useFreeMoney = (WrappedComponent) => { class WithFreeMoney extends React.Component { giveFreeMoney() { return 50000 } render() { return ( <WrappedComponent additionalMoney={[ this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), this.giveFreeMoney(), ]} {...this.props} /> ) } } WithFreeMoney.displayName = `useFreeMoney(${getDisplayName( WrappedComponent, )}$)` hoistNonReactStatics(WithFreeMoney, WrappedComponent) return WithFreeMoney } export default useFreeMoney
هذا هو رمز جافا سكريبت وظيفية تماما. الأسماء هنا مصنوعة ، من الناحية الفنية ، إلى اليمين. لكن بادئة
use
مألوفة لاستخدامها في المواقف الأخرى ، أي عند تسمية
خطافات React . نتيجة لذلك ، إذا كتب شخص ما برنامجًا يخطط لعرضه لشخص آخر ، فينبغي أن يكون حريصًا على أسماء الكيانات. وينطبق هذا بشكل خاص على تلك الحالات عندما يطلب شخص ما رؤية رمزه ومساعدته على حل مشكلة. والحقيقة هي أن شخصًا ما يقرأ رمز شخص آخر ، على الأرجح ، مستخدم بالفعل في نظام تسمية كيان معين.
الانحرافات عن المعايير المقبولة عمومًا تجعل من الصعب فهم كود شخص آخر.
4. تجنب الفخاخ المنطقية
يجب أن يتوخى المبرمج الحذر الشديد في حالة اعتماد بعض المخرجات على بعض القيم المنطقية البدائية ، ويتم اتخاذ بعض القرارات بناءً على تحليل هذه القيم. هذا يلمح إلى النوعية الرديئة للكود. هذا يفرض على المطورين قراءة التعليمات البرمجية لتطبيق المكونات أو الآليات الأخرى للحصول على فكرة دقيقة عن ماهية نتائج هذه الآليات.
افترض أننا أنشأنا مكونًا
Typography
يمكنه قبول الخيارات التالية:
'h1'
،
'h2'
،
'h3'
،
'h4'
،
'h5
' ،
'h6'
،
'title'
،
'subheading'
.
ما الذي سيؤثر بالضبط على ناتج المكون إذا تم تمرير الخيارات إليه في النموذج التالي؟
const App = () => ( <Typography color="primary" align="center" subheading title> Welcome to my bio </Typography> )
أولئك الذين لديهم بعض الخبرة في React (أو بالأحرى مع JavaScript) قد يفترضون بالفعل أن خيار
title
subheading
خيار
subheading
نظرًا لطريقة عمل النظام. سوف الخيار الأخير الكتابة فوق الأول.
لكن المشكلة هنا هي أنه لا يمكننا ، دون النظر إلى الكود ، أن نقول بالضبط إلى أي مدى سيتم تطبيق خيار
title
أو خيار
title
subheading
.
على سبيل المثال:
.title { font-size: 1.2rem; font-weight: 500; text-transform: uppercase; } .subheading { font-size: 1.1rem; font-weight: 400; text-transform: none !important; }
على الرغم من فوز
title
، فإن
text-transform: uppercase
CSS
text-transform: uppercase
لن يتم تطبيق قاعدة
text-transform: uppercase
. هذا بسبب خصوصية
text-transform: none !important
قاعدة
text-transform: none !important
موجودة في
subheading
. إذا لم تمارس الحذر في مثل هذه الحالات ، فقد يصبح تصحيح هذه الأخطاء في الأنماط أمرًا بالغ الصعوبة. خاصة - في الحالات التي لا يعرض فيها الكود بعض التحذيرات أو رسائل الخطأ في وحدة التحكم. هذا يمكن أن يعقد توقيع المكون.
أحد الحلول الممكنة لهذه المشكلة هو استخدام نسخة أنظف من مكون
Typography
:
const App = () => <Typography variant="title">Welcome to my bio</Typography>
هنا هو رمز مكون
Typography
:
import React from 'react' import cx from 'classnames' import styles from './styles.css' const Typography = ({ children, color = '#333', align = 'left', variant, ...otherProps }) => { return ( <div className={cx({ [styles.h1]: variant === 'h1', [styles.h2]: variant === 'h2', [styles.h3]: variant === 'h3', [styles.h4]: variant === 'h4', [styles.h5]: variant === 'h5', [styles.h6]: variant === 'h6', [styles.title]: variant === 'title', [styles.subheading]: variant === 'subheading', })} > {children} </div> ) }
الآن ، عندما ننتقل إلى مكون
App
إلى
Typography
component
variant="title"
، يمكننا أن نتأكد من أن
title
فقط هو الذي سيؤثر على إخراج المكون. هذا يوفر علينا من الاضطرار إلى تحليل رمز المكون من أجل فهم كيف سيبدو هذا المكون.
للعمل مع الخصائص ، يمكنك استخدام التصميم البسيط
if/else
:
let result if (variant === 'h1') result = styles.h1 else if (variant === 'h2') result = styles.h2 else if (variant === 'h3') result = styles.h3 else if (variant === 'h4') result = styles.h4 else if (variant === 'h5') result = styles.h5 else if (variant === 'h6') result = styles.h6 else if (variant === 'title') result = styles.title else if (variant === 'subheading') result = styles.subheading
لكن القوة الرئيسية لهذا النهج هي أنه يمكنك ببساطة استخدام التصميم الفريد النظيف التالي ووضع حد له:
const result = styles[variant]
5. استخدام وظائف السهم
تمثل وظائف السهم آلية موجزة وواضحة لإعلان الوظائف في جافا سكريبت (في هذه الحالة ، سيكون من الأصح التحدث عن ميزة وظائف السهم على التعبيرات الوظيفية).
ومع ذلك ، في بعض الحالات ، لا يستخدم المطورون وظائف السهم بدلاً من التعبيرات الوظيفية. على سبيل المثال ، عندما يكون ذلك ضروريا لتنظيم رفع الوظائف.
React يستخدم هذه المفاهيم بطريقة مماثلة. ومع ذلك ، إذا لم يكن مبرمجًا مهتمًا برفع الوظائف ، في رأيي ، من المنطقي استخدام بناء جملة وظائف السهم:
تجدر الإشارة إلى أنه ، عند تحليل هذا المثال ، يصعب رؤية نقاط قوة وظائف السهم. يتجلى جمالهم بشكل كامل عندما يتعلق الأمر بالتصاميم البسيطة المفردة:
أنا متأكد من أن مثل هذه التصميمات أحادية الخط ستجذب الجميع.
6. ضع وظائف مستقلة خارج السنانير الخاصة بك
لقد رأيت كيف يعلن بعض المبرمجين وظائفهم داخل خطاطيفهم ، لكن هذه الخطافات لا تحتاج بشكل خاص إلى مثل هذه الوظائف. هذا النوع من "ينفخ" قليلا رمز هوك ويعقد قراءتها. تنشأ صعوبات في قراءة الكود بسبب حقيقة أن قراءها قد يبدأون في طرح أسئلة حول ما إذا كان الخطاف يعتمد حقًا على الوظيفة الموجودة بداخله. إذا لم يكن الأمر كذلك ، فمن الأفضل تحريك الوظيفة خارج الخطاف. سيعطي هذا لقارئ التعليمات البرمجية فهمًا واضحًا لما يعتمد عليه الخطاف وما لا يعتمد عليه.
هنا مثال:
import React from 'react' const initialState = { initiated: false, images: [], } const reducer = (state, action) => { switch (action.type) { case 'initiated': return { ...state, initiated: true } case 'set-images': return { ...state, images: action.images } default: return state } } const usePhotosList = ({ imagesList = [] }) => { const [state, dispatch] = React.useReducer(reducer, initialState) const removeFalseyImages = (images = []) => images.reduce((acc, img) => (img ? [...acc, img] : acc), []) React.useEffect(() => { const images = removeFalseyImages(imagesList) dispatch({ type: 'initiated' }) dispatch({ type: 'set-images', images }) }, []) return { ...state, } } export default usePhotosList
إذا قمنا بتحليل هذا الرمز ، يمكننا أن نفهم أن وظائف
removeFalseyImages
، في الواقع ، لا يجب أن تكون موجودة داخل الخطاف ؛ فهي لا تتفاعل مع حالتها ، مما يعني أنه يمكن وضعها خارجها ويمكن استدعاؤها من الخطاف دون أي مشاكل.
7. أن تكون متسقة عند كتابة التعليمات البرمجية
يعد الأسلوب الثابت لكتابة التعليمات البرمجية أمرًا موصى به غالبًا لأولئك الذين يبرمجون في JavaScript.
في حالة React ، يجدر الانتباه إلى نهج ثابت لاستخدام التصميمات التالية:
- فرق الاستيراد والتصدير.
- تسمية المكونات ، والسنانير ، ومكونات النظام العالي ، والطبقات.
عند استيراد المكونات وتصديرها ، أحيانًا أستخدم شيئًا مشابهًا لما يلي:
import App from './App' export { default as Breadcrumb } from './Breadcrumb' export default App
لكني أحب بناء الجملة أيضًا:
export { default } from './App' export { default as Breadcrumb } from './Breadcrumb'
أياً كان ما يختاره المبرمج ، فيجب عليه استخدامه باستمرار في كل مشروع يقوم بإنشائه. هذا يبسط عمل هذا المبرمج وقراءة الكود من قبل أشخاص آخرين.
من المهم للغاية الالتزام بتسمية اصطلاحات الكيانات.
على سبيل المثال ، إذا أعطى شخص ما
useApp
اسم
useApp
، فمن المهم أن يتم إنشاء أسماء الخطافات الأخرى بطريقة مماثلة - باستخدام بادئة الاستخدام. على سبيل المثال ، قد يبدو اسم ربط آخر مع هذا الأسلوب
useController
.
إذا لم تلتزم بهذه القاعدة ، فقد يتحول رمز المشروع في النهاية إلى شيء من هذا القبيل:
إليك ما يبدو عليه استيراد هذه السنانير:
import React from 'react' import useApp from './useApp' import basicController from './basicController' const App = () => { const app = useApp() const controller = basicController() return ( <div> {controller.errors.map((errorMsg) => ( <div>{errorMsg}</div> ))} </div> ) } export default App
للوهلة الأولى ، من غير
basicController
تمامًا أن
basicController
هو خطاف ، تمامًا مثل
useApp
. هذا يفرض على المطور قراءة رمز التنفيذ لما يستورده. يتم ذلك فقط لفهم ما يتعامل معه المطور بالضبط. إذا التزمنا باستمرار بنفس الاستراتيجية لتسمية الكيانات ، فلن ينشأ مثل هذا الموقف. كل شيء سيكون واضحا في لمحة:
const app = useApp() const controller = useBasicController()
أن تستمر ...
أعزائي القراء! كيف يمكنك التعامل مع تسمية الكيان في مشاريع React الخاصة بك؟
