Найбільш обгрунтований підхід до React та JSX
- Основні правила
- Class проти
React.createClass
проти безстейтового компонента - Іменування
- Оголошення
- Вирівнювання
- Лапки
- Пробіли
- Властивості - Props
- Посилання - Refs
- Дужки
- Теги
- Методи
- Послідовність
isMounted
- Включайте лише один React компонент у файл.
- Проте, дозволяється кілька Безстейтових чи чистих компонент у файлі. eslint:
react/no-multi-comp
.
- Проте, дозволяється кілька Безстейтових чи чистих компонент у файлі. eslint:
- Завжди використовуйте JSX синтаксис.
- Не використовуйте
React.createElement
, якщо тільки ви не ініціалізуєте програму з файлу, який не є JSX.
-
Якщо у вас є внутрішній state та/або refs, віддавайте перевагу
class extends React.Component
, а неReact.createClass
, хіба що ви маєте надзвичайно вагомі причини використати міксіни. eslint:react/prefer-es6-class
react/prefer-stateless-function
// погано const Listing = React.createClass({ // ... render() { return <div>{this.state.hello}</div>; } }); // добре class Listing extends React.Component { // ... render() { return <div>{this.state.hello}</div>; } }
І якщо ви не маєте state чи refs, віддавайте перевагу звичайним функціям (не стрілочним функціям), а не класам:
// погано 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>; }
-
Розширення: Використовуйте
.jsx
розширення для React компонентів. -
Назва файлу: Використовуйте PascalCase для назв файлів. Наприклад:
ReservationCard.jsx
. -
Іменування посиланнь: Використовуйте PascalCase для React компонентів та camelCase для їх екземплярів. eslint:
react/jsx-pascal-case
// погано import reservationCard from './ReservationCard'; // добре import ReservationCard from './ReservationCard'; // погано const ReservationItem = <ReservationCard />; // добре const reservationItem = <ReservationCard />;
-
Іменування компонентів: Використовуйте назву файла в якості назви компонента. Наприклад, назва файлу
ReservationCard.jsx
повинна посилатись на назву компонентаReservationCard
. Проте, для кореневих компонентів директорії, використовуйтеindex.jsx
як назву файла та використовуйте назву директорії в якості назви компонента:// погано import Footer from './Footer/Footer'; // погано import Footer from './Footer/index'; // добре import Footer from './Footer';
-
Іменування компонент верхнього порядку (Higher-order Component): Використовуйте поєднання назви компонента верхнього порядку та назви компонента переданого в нього для утворення
displayName
згенерованого компонента. Наприклад, коли в компонент верхнього порядкуwithFoo()
передають компонентBar
, то має згенеруватись компонент зdisplayName
withFoo(Bar)
.
Чому?
displayName
компонента може бути використано у developer tools, або у повідомленні про помилку, і в разі, коли воно має значення, котре чітко виражає цей звязок - це допомогає людям зрозуміти, що відбувається.
```jsx
// погано
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
означають одну конкретну річ. Використання цього API для власних цілей робить код менш читабельним та менш підтримуваним, а також може призвести до багів.
```jsx
// погано
<MyComponent style="fancy" />
// добре
<MyComponent variant="fancy" />
```
-
Не використовуйте
displayName
для іменування компонентів. Натомість, називайте компонент за посиланням.// погано export default React.createClass({ displayName: 'ReservationCard', // все інше тут }); // добре export default class ReservationCard extends React.Component { }
-
Використовуйте ці стилі вирівнювання для JSX синтаксису. eslint:
react/jsx-closing-bracket-location
// погано <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // добре <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // якщо властивості вміщуються у одну строчку, тоді лишайте їх на тій самій лінії <Foo bar="bar" /> // нащадки вирівнюються нормально <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
- Завжди використовуйте подвійні лапки (
"
) для JSX атрибутів, але одинарні лапки ('
) для решти JS. eslint:jsx-quotes
Чому? Звичайні HTML атрибути також використовують подвійні лапки замість одинарних, тож JSX атрибути відзеркалюють цю конвенцію.
```jsx
// погано
<Foo bar='bar' />
// добре
<Foo bar="bar" />
// погано
<Foo style={{ left: "20px" }} />
// добре
<Foo style={{ left: '20px' }} />
```
-
Завжди додавайте один пробіл у ваш самозакривающийся тег. eslint:
no-multi-spaces
,react/jsx-space-before-closing
// погано <Foo/> // дуже погано <Foo /> // погано <Foo /> // добре <Foo />
-
Не робіть відступи пробілом усередині фігурних дужок JSX. eslint:
react/jsx-curly-spacing
// погано <Foo bar={ baz } /> // добре <Foo bar={baz} />
-
Завжди використовуйте camelCase для назв властивостей.
// погано <Foo UserName="hello" phone_number={12345678} /> // <Foo userName="hello" phoneNumber={12345678} />
-
Не зазначайте значення властивості у випадку, коли воно явно
true
. eslint:react/jsx-boolean-value
// погано <Foo hidden={true} /> // добре <Foo hidden />
-
Завжди додавайте властивість
alt
до тегу<img>
. Якщо зображення є презентаційним,alt
може бути порожньою строчкою, або ж<img>
мусить мати атрибутrole="presentation"
. eslint:jsx-a11y/img-has-alt
// погано <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" у
<img>
в якості властивостіalt
. eslint:jsx-a11y/img-redundant-alt
Чому? Зчитувачі екранів вже оголошують
img
елементи як зображення, тож немає необхідності включати цю інформацію до атрибутуalt
.
```jsx
// погано
<img src="hello.jpg" alt="Picture of me waving hello" />
// добре
<img src="hello.jpg" alt="Me waving hello" />
```
-
Використовуйте лише валідні, не абстрактні ARIA roles. eslint:
jsx-a11y/aria-role
// погано - не є ARIA role <div role="datepicker" /> // погано - абстрактний ARIA role <div role="range" /> // добре <div role="button" />
-
Не використовуйте
accessKey
на елементах. eslint:jsx-a11y/no-access-key
Чому? Невідповідності між поєднанням комбінацій клавіш та командами з клавіатури, ускладнюють доступ для людей, котрі користуються екранними зчитувачами та клавіатурами.
// погано
<div accessKey="h" />
// добре
<div />
- Уникайте використання індексів елементів масиву в якості властивості
key
, та віддавайте перевагу унікальному ID. (Чому?)
// погано
{todos.map((todo, index) =>
<Todo
{...todo}
key={index}
/>
)}
// добре
{todos.map(todo => (
<Todo
{...todo}
key={todo.id}
/>
))}
- Завжди зазначайте явні defaultProps для всіх властивостей, котрі не зазначені як необхідні (не зазначені як
isRequired
).
Чому? propTypes - це спосіб документації і зазначення 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 }) {
return <div>{foo}{bar}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
};
SFC.defaultProps = {
bar: '',
children: null,
};
-
Завжди використовуйте зворотні виклики ref. eslint:
react/no-string-refs
// погано <Foo ref="myRef" /> // добре <Foo ref={(ref) => { this.myRef = ref; }} />
-
Обгортайте JSX теги дужками, коли вони займають більше ніж одну лінію. eslint:
react/wrap-multilines
// погано render() { return <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent>; } // добре render() { return ( <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent> ); } // добре, коли одна строчка render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
-
Завжди самозакривайте теги, котрі не мають нащадків. eslint:
react/self-closing-comp
// погано <Foo className="stuff"></Foo> // добре <Foo className="stuff" />
-
Якщо ваш компонент має властивості, котрі займають кілька строчок, закривайте тег на новій строчці. eslint:
react/jsx-closing-bracket-location
// погано <Foo bar="bar" baz="baz" /> // добре <Foo bar="bar" baz="baz" />
-
Використовуйте стрілочні функції для замкнення локальних змінних.
function ItemList(props) { return ( <ul> {props.items.map((item, index) => ( <Item key={item.key} onClick={() => doSomethingWith(item.name, index)} /> ))} </ul> ); }
-
Прив’язуйте обробники подій для метода render у конструкторі. eslint:
react/jsx-no-bind
Чому? Виклик bind у render створює нову функцію при кожному рендері.
```jsx
// погано
class extends React.Component {
onClickDiv() {
// щось виконується
}
render() {
return <div onClick={this.onClickDiv.bind(this)} />
}
}
// добре
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// щось виконується
}
render() {
return <div onClick={this.onClickDiv} />
}
}
```
- Не використовуйте префікс підкреслення для внутрішніх методів у React компоненті.
Чому? Префікси підкреслення інколи використовуються у інших мовах як конвенція з відзначення приватності. Але, на відміну від тих мов, у JavaScript немає рідної підтримки приватності, тому все - публічне. Незалежно від ваших намірів, додавання префіксу підкреслення до ваших властивостей не робить їх приватними, і будь-яка властивість (з префіксом підкреслення чи без) повинна розглядатись як загальнодоступна. Дивіться питання #1024, та #490 з більш детальним обговоренням.
```jsx
// погано
React.createClass({
_onClickSubmit() {
// щось виконується
},
// виконується ще щось
});
// добре
class extends React.Component {
onClickSubmit() {
// щось виконується
}
// виконується ще щось
}
```
-
Переконайтесь, що ви повертаєте значення у ваших
render
методах. eslint:react/require-render-return
// погано render() { (<div />); } // добре render() { return (<div />); }
- Послідовність для
class extends React.Component
:
- Довільні
static
методи constructor
getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
- обробники кліків та подій, такі як
onClickSubmit()
чиonChangeDescription()
- getter методи для
render
, такі якgetSelectReason()
чиgetFooterContent()
- довільні render методи, такі як
renderNavigation()
абоrenderProfilePicture()
render
-
Як зазначати
propTypes
,defaultProps
,contextTypes
, і т.д.import React, { PropTypes } from 'react'; 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
: eslint:react/sort-comp
displayName
propTypes
contextTypes
childContextTypes
mixins
statics
defaultProps
getDefaultProps
getInitialState
getChildContext
componentWillMount
componentDidMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
componentWillUnmount
- обробники кліків чи подій, такі як
onClickSubmit()
абоonChangeDescription()
- getter методи для
render
, такі якgetSelectReason()
чиgetFooterContent()
- довільні render методи, такі як
renderNavigation()
чиrenderProfilePicture()
render
- Не використовуйте
isMounted
. eslint:react/no-is-mounted
Чому?
isMounted
це анти-паттерн, і він не доступний при використанні ES6 класів, і його планується офіційно скасувати.
Це керівництво JSX/React стилями також доступне іншими мовами:
English: airbnb/javascript
Chinese (Simplified): JasonBoy/javascript
Polish: pietraszekl/javascript
Korean: apple77y/javascript
Portuguese: ronal2do/javascript
Japanese: mitsuruog/javascript-style-guide
Español: agrcrobles/javascript
Ukrainian: ivanzusko/javascript