القواعد الأساسية
-
لا تضع إلا مكوِّن React واحدًا فقط في كل ملف.
- مع ذلك، يُسمح بوضع أكثر من مكوّن من الدوال عديمة الحالة (Stateless functions) في ملف واحد. استعن بقاعدة react/no-multi-comp في ESLint.
- استخدم دائمًا أسلوب الصياغة JSX.
-
لا تستخدم التابع
React.createElement
إلا إذا كنت تهيئ التطبيق من ملف لا يستخدم صياغة JSX.
Class مقابل React.createClass مقابل stateless
-
استخدم
class extends React.Component
بدلًا منReact.createClass
إذا كانت لديك حالة أو مراجع (Refs) داخلية أو هما معًا.// سيّئ const Listing = React.createClass({ // ... render() { return <div>{this.state.hello}</div>; } }); // جيّد class Listing extends React.Component { // ... render() { return <div>{this.state.hello}</div>; } }
-
أما إذا لم تكن لديك حالة داخلية أو مرجعية، فمن الأفضل استخدام الدوال العادية (وليس الدوال السهمية) بدلًا من استخدام الأصناف.
// سيّئ class Listing extends React.Component { render() { return <div>{this.props.hello}</div>; } } // سيّئ (يُنصَح بعدم الاعتماد على استنباط اسم الدالة) const Listing = ({ hello }) => ( <div>{hello}</div> ); // جيّد function Listing({ hello }) { return <div>{hello}</div>; }
الخلائط (Mixins)
-
تجنب استخدام الخلائط.
- لماذا؟ لأنها تنطوي على اعتمادات (Dependencies) ضمنية، كما قد تتسبب في اشتباك الأسماء، وترفع درجة التعقيد. يمكن استبدال الخلائط في معظم الحالات بطرق أفضل عبر المكوّنات (Components)، أو المكوّنات ذات المستوى العالي (Higher-order components) أو الوحدات المساعدة.
التسمية
-
الامتدادات: استخدم الامتداد
jsx.
لمكوّنات React . -
اسم الملف: استخدم أسلوب التسمية PascalCase لأسماء الملفات. على سبيل المثال،
ReservationCard.jsx
. - تسمية المراجع: استخدم أسلوب التسمية PascalCase لمكوّنات React وأسلوب camelCase لنسخ الكائنات (Instances).
// سيّئ import reservationCard from './ReservationCard'; // جيّد import ReservationCard from './ReservationCard'; // سيّئ const ReservationItem = <ReservationCard />; // جيّد const reservationItem = <ReservationCard />;
-
تسمية المكوّنات: استخدم اسم الملف كاسم للمكوّن. على سبيل المثال،
ReservationCard.jsx
ينبغي أن يكون اسم مرجعهاReservationCard
. بالنسبة للمكوّنات الجذرية للمجلد (Root components)، استخدمindex.jsx
لاسم للملف واستخدم اسم المجلد لاسم المكوّن:
// سيّئ import Footer from './Footer/Footer'; // سيّئ import Footer from './Footer/index'; // جيّد import Footer from './Footer';
-
تسمية المكوّنات ذات المستوى العالي (Higher-order Componen): استخدم مزيجًا من اسم المكوّن ذي المستوى العالي واسم المكوِّن المُمرَّر ليكون قيمة الخاصيّة
displayName
في المكوّن المُولَّد.على سبيل المثال، إذا مُرّر للمكوّن ذي المستوى العالي()withFoo
المكوّن Bar فإن الناتج ستكون قيمة الخاصيّةdisplayName
لديه هيwithFoo(Bar)
.لماذا ا؟ يمكن استخدام الخاصيّة
displayName
في أدوات المطوّرين أو في رسائل الخطأ، وعندما تعكس قيمتها تلك العلاقة بوضوح، فسيساعد ذلك على فهم ما يحدث.
// سيّئ export default function withFoo(WrappedComponent) { return function WithFoo(props) { return <WrappedComponent {...props} foo />; } } // جيّد export default function withFoo(WrappedComponent) { function WithFoo(props) { return <WrappedComponent {...props} foo />; } const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; WithFoo.displayName = `withFoo(${wrappedComponentName})`; return WithFoo; }
-
تسمية الخاصيّات (Props) : تجنب استعمال أسماء مكوّنات DOM لأغراض مختلفة. لماذا؟ يتوقع المطوّرون أنّ خاصيّات مثل
style
وclassName
تعني أشياء محددة. تغيير الواجهة البرمجية هذه في جزء من تطبيقك يجعل الشفرة البرمجية أقل قابلية للقراءة والصيانة، ويمكن أن يتسبب في أعطاب.// سيّئ <MyComponent style="fancy" /> // جيّد <MyComponent className="fancy" /> // جيّد <MyComponent variant="fancy" />
التصريح Declaration
-
لا تستخدم
displayName
لتسمية المكوّنات. بدلًا من ذلك، سمّ المكوّنات بمراجعها.// سيّئ export default React.createClass({ displayName: 'ReservationCard', // stuff goes here }); // جيّد export default class ReservationCard extends React.Component { }
المحاذاة Alignment
-
اتبع الأساليب التالية للمحاذاة في صياغة JSX. استعن بقاعدتيْ react/jsx-closing-bracket-location وreact/jsx-closing-tag-location في ESLint.
// سيّئ <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // جيّد <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // if props fit in one line then keep it on the same line <Foo bar="bar" /> // children get indented normally <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
الاقتباس Quotes
-
استخدم دائمًا علامات الاقتباس المزدوجة (
"
) لخاصيّات JSX، وعلامات الاقتباس المفردة ('
) لبقية عناصر جافاسكريبت. استعن بقاعدة jsx-quotes في ESLint.لماذا؟ تستخدم خاصيّات HTML عادةً علامات الاقتباس المزدوجة بدلًا من المفردة، لذا فخاصيّات JSX تتبع هذا الاصطلاح.
// سيّئ <Foo bar='bar' /> // جيّد <Foo bar="bar" /> // سيّئ <Foo style={{ left: "20px" }} /> // جيّد <Foo style={{ left: '20px' }} />
إدراج المسافات Spacing
-
أضف دائمًا مسافةً واحدةً في الوسوم المنغلقة على ذاتها (Self-closing tags). استعن بالقاعدتين no-multi-spaces وreact/jsx-tag-spacing.
// سيّئ <Foo/> // سيّئ جدًّا <Foo /> // سيّئ <Foo /> // جيّد <Foo />
-
لا تحش أقواس JSX المعقوصة بمسافات. استعن بالقاعدة react/jsx-curly-spacing.
// سيّئ <Foo bar={ baz } /> // جيّد <Foo bar={baz} />
الخاصيات Props
-
استخدم دائمًا أسلوب التسمية camelCase لتسمية الخاصيّات.
// سيّئ <Foo UserName="hello" phone_number={12345678} /> // جيّد <Foo userName="hello" phoneNumber={12345678} />
-
احذف قيمة الخاصيّة عندما تكون قيمتها تساوي
true
على نحو صريح. استعن بالقاعدة react/jsx-boolean-value.// سيّئ <Foo hidden={true} /> // جيّد <Foo hidden /> // جيّد <Foo hidden />
-
أضف دومًا الخاصيّة
alt
في وسوم الصور(<img>
). إذا كانت الصورة تقديمية (Presentational)، فيمكن للخاصيّةalt
أن تكون نصًّا فارغًا وإلّا فيجب أن يحتوي الوسم<img>
على الخاصيّة role="presentation".// سيّئ <img src="hello.jpg" /> // جيّد <img src="hello.jpg" alt="Me waving hello" /> // جيّد <img src="hello.jpg" alt="" /> // جيّد <img src="hello.jpg" role="presentation" />
-
لا تستخدم كلمات مثل "image" أو "photo " أو "picture" أو "صورة" في خاصيّات
alt
الخاصة بوسوم<img>
. استعن بالقاعدة jsx-a11y/img-redundant-alt.لماذا؟ تعلم برامج قراءة الشاشة أن
<img>
تعني صورة، لذلك لا توجد حاجة لإدراج هذه المعلومة في النص البديل (alt text).// سيّئ <img src="hello.jpg" alt="صورة مني وأنا أشير بيدي للترحيب" /> // جيّد <img src="hello.jpg" alt="أشير بيدي للترحيب" />
-
لا تستخدم إلّا أدوار ARIA الصالحة وغير المجردة. استعن بالقاعدة jsx-a11y/aria-role.
// سيّئ، ليس من أدوار ARIA <div role="datepicker" /> // سيّئ، دور ARIA مجرّد <div role="range" /> // جيّد <div role="button" />
-
لا تستخدم الخاصيّة
accesskey
على العناصر. استعن بالقاعدة jsx-a11y/no-access-key.لماذا؟ تعقّد التناقضات بين اختصارات لوحة المفاتيح وأوامر لوحة المفاتيح التي يستعملها مَن يستخدمون برامج قراءة الشاشة ولوحة المفاتيح، تعقّد قابلية الوصول (Accessibility).
// سيّئ <div accessKey="h" /> // جيّد <div />
-
تجنب استخدام فهرس مصفوفة (Array index) ليكون خاصيّة
key
. استخدم معرّفًا فريدًا بدلًا من ذلك. (لماذا؟).// سيّئ {todos.map((todo, index) => <Todo {...todo} key={index} /> )} // جيّد {todos.map(todo => ( <Todo {...todo} key={todo.id} /> ))}
-
عرّف دائمًا قيمًا افتراضيّة (
defaultProps
) للخاصيّات غير المطلوبة.
لماذا؟ تعدّ القيم الافتراضيّة وسيلة للتوثيق، وتوفيرها سيجنّب قارئ الشفرة البرمجية كثيرًا من التخمينات. علاوةً على ذلك، قد يعني تعيين القيم الافتراضية أنك تستطيع الاستغناء عن التحقق في نوع البيانات أحيانا.
// سيّئ function SFC({ foo, bar, children }) { return <div>{foo}{bar}{children}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; // جيّد function SFC({ foo, bar, children }) { return <div>{foo}{bar}{children}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; SFC.defaultProps = { bar: '', children: null, };
-
عرّف دائمًا قيمًا افتراضيّة (
-
لا تُسرف في استخدام الخاصيّات الممدَّدة (Spread props).
لماذا؟ لكي تتجنب قدر الإمكان تمرير الخاصيّات التي لا داعي لها إلى المكوّنات. بالنسبة للإصدار React v15.6.1 والإصدارت الأقدم، ستتجنب كذلك تمرير سمات HTML غير صالحة إلى نموذج DOM.
استثناءات:
-
المكوّنات ذات المستوى العالي التي تغلّف الخاصيّات وترفع الخاصيّة
propTypes
إلى أعلى النطاق (Hoist):function HOC(WrappedComponent) { return class Proxy extends React.Component { Proxy.propTypes = { text: PropTypes.string, isLoading: PropTypes.bool }; render() { return <WrappedComponent {...this.props} /> } } }
-
تمديد الكائنات بخاصيّات معروفة وواضحة يمكن أن يكون مفيدًا خصوصًا عند اختبار مكوّنات React بالتركيب
forEach
في Mocha.export default function Foo { const props = { text: '', isPublished: false } return (<div {...props} />); }
-
ملحوظة: حاول تصفية الخاصيّات التي لا داعي لها، واستخدم prop-types-exact لمساعدتك على تجنب العلل.
// جيّد render() { const { irrelevantProp, ...relevantProps } = this.props; return <WrappedComponent {...relevantProps} /> } // سيّئ render() { const { irrelevantProp, ...relevantProps } = this.props; return <WrappedComponent {...this.props} /> }
المرجعيّات Refs
-
استخدم دائمًا رد نداء (Callback) للمراجع (Refs). استعن بالقاعدة react/no-string-refs.
// سيّئ <Foo ref="myRef" /> // جيّد <Foo ref={(ref) => { this.myRef = ref; }} />
الأقواس
-
ضع وسوم JSX بين أقواس إذا امتدت على أكثر من سطر واحد. استعن بالقاعدة react/jsx-wrap-multilines.
// سيّئ render() { return <MyComponent variant="long body" foo="bar"> <MyChild /> </MyComponent>; } // جيّد render() { return ( <MyComponent variant="long body" foo="bar"> <MyChild /> </MyComponent> ); } // جيّد، بالنسبة لسطر واحد render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
الوسوم Tags
-
استخدم دائمًا الإغلاق الذاتي (Self-close) للوسوم التي لا أبناء لها. استعن بالقاعدة react/self-closing-comp.
// سيّئ <Foo variant="stuff"></Foo> // جيّد <Foo variant="stuff" />
-
اجعل إغلاق الوسوم في سطر جديد إذا كان للمكوّن خاصيّات متعددة الأسطر. استعن بالقاعدة react/jsx-closing-bracket-location.
// سيّئ <Foo bar="bar" baz="baz" /> // جيّد <Foo bar="bar" baz="baz" />
التوابع Methods
-
استخدم الدوال السهمية في المتغيرات المحلية.
function ItemList(props) { return ( <ul> {props.items.map((item, index) => ( <Item key={item.key} onClick={() => doSomethingWith(item.name, index)} /> ))} </ul> ); }
-
اربط معالجات الأحداث الخاصّة بتابع التصيير (Render methode) داخل المنشئ. استعن بالقاعدة react/jsx-no-bind.
لماذا؟ استدعاء
bind
في مسار التصيير (Render path) يُنشئ دالة جديدة لكل تابع تصيير.// سيّئ class extends React.Component { onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv.bind(this)} />; } } // جيّد class extends React.Component { constructor(props) { super(props); this.onClickDiv = this.onClickDiv.bind(this); } onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv} />; } }
-
لا تستخدم الشرطة السفلية (_) في بداية أسماء التوابع الداخلية لمكوّنات React .
لماذا؟ تُستخدَم الشرطات السفلية في بداية أسماء المتغيّرات في لغات أخرى للدلالة على الخصوصية. ولكن، خلافًا لتلك اللغات، لا يوجد دعم أصيل للخصوصية في جافاسكريبت، فكل شيء فيها عام. إضافة شرطة سفلية في بداية أسماء الخاصيات، بغض النظرعن نواياك، لا يجعلها خاصة، ويجب أن تُعامَل كل الخاصيات (مسبوقة بالشرطة السفلية أو لا) على أنها عامة. انظر إلى النقاش حول 1024# وenter link description here للتعمّق.
// سيّئ React.createClass({ _onClickSubmit() { // do stuff }, // other stuff }); // جيّد class extends React.Component { onClickSubmit() { // do stuff } // other stuff }
-
تأكد من إرجاع قيمة في توابع التصيير. استعن بالقاعدة react/require-render-return.
// سيّئ render() { (<div />); } // جيّد render() { return (<div />); }
الترتيب Ordering
-
الترتيب عند تمديد الصنف
React.Component
لإنشاء مكوّن React جديد (class extends React.Component
):
-
التوابع الثابتة (
static
) الاختيارية، -
constructor
-
getChildContext
-
componentWillMount
-
componentDidMount
-
componentWillReceiveProps
-
shouldComponentUpdate
-
componentWillUpdate
-
componentDidUpdate
-
componentWillUnmount
-
معالجات الأحداث والنقر مثل
onClickSubmit()
أوonChangeDescription()
-
توابع الوصول الخاصة بـ
render
مثلgetSelectReason()
أوgetFooterContent()
-
توابع
render
الاختيارية مثلrenderNavigation()
أوrenderProfilePicture()
. -
render
.
-
كيفية تعريف
propTypes
وdefaultProps
وcontextTypes
import React from 'react'; import PropTypes from 'prop-types'; const propTypes = { id: PropTypes.number.isRequired, url: PropTypes.string.isRequired, text: PropTypes.string, }; const defaultProps = { text: 'Hello World', }; class Link extends React.Component { static methodsAreOk() { return true; } render() { return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>; } } Link.propTypes = propTypes; Link.defaultProps = defaultProps; export default Link;
• الترتيب الخاص بـ React.createClass. استعن بالقاعدة react/sort-comp.
-
displayName
-
propTypes
-
contextTypes
-
childContextTypes
-
mixins
-
statics
-
defaultProps
-
getDefaultProps
-
getInitialState
-
getChildContext
-
componentWillMount
-
componentDidMount
-
componentWillReceiveProps
-
shouldComponentUpdate
-
componentWillUpdate
-
componentDidUpdate
-
componentWillUnmount
-
معالجات الأحداث والنقر مثل
onClickSubmit()
أوonChangeDescription()
-
توابع الوصول الخاصة بـ
render
مثلgetSelectReason()
أوgetFooterContent()
-
توابع
render
الاختيارية مثلrenderNavigation()
أوrenderProfilePicture()
. -
render
-
لا تستخدم
isMounted
. استعن بالقاعدة react/no-is-mountedلماذا؟ استخدام
isMounted
غير مجدٍ (Anti-pattern)، وهو غير متوفر عند استخدام أصناف ES6، كما أنه سيُلغى رسميًّا قريبا.
ترجمة - وبتصرّف - للمقال Airbnb React/JSX Style Guide.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.