A mostly reasonable approach to React and JSX
- Базовые правила
- Class vs
React.createClassvs stateless - Именование
- Объявление
- Отступы
- Кавычки
- Пробелы
- Props
- Refs
- Скобки
- Тэги
- Методы
- Сортировка
isMounted
- Всегда включайте компонент в отдельный файл.
- However, multiple Stateless, or Pure, Components are allowed per file. eslint:
react/no-multi-comp.
- However, multiple Stateless, or Pure, Components are allowed per file. eslint:
- Всегда используйте JSX синтаксис.
- Не используйте
React.createElementв JSX файлах.
-
Если у вас есть внутренний state и/или refs, предпочтительно использовать
class extends React.Componentа неReact.createClassиначе у вас должна быть очень хорошая причина использовать примеси (mixins). eslint:react/prefer-es6-classreact/prefer-stateless-function// bad const Listing = React.createClass({ // ... render() { return <div>{this.state.hello}</div>; } }); // good class Listing extends React.Component { // ... render() { return <div>{this.state.hello}</div>; } }
И если вам не нужен state или refs, используйте стандартные функции (не стрелочные) а не классы:
// bad class Listing extends React.Component { render() { return <div>{this.props.hello}</div>; } } // bad (relying on function name inference is discouraged) const Listing = ({ hello }) => ( <div>{hello}</div> ); // good function Listing({ hello }) { return <div>{hello}</div>; }
-
Расширения: Используйте расширение
.jsxдля файлов React компонентов. -
Имена файлов: Используйте PascalCase в именах файлов. Например
ReservationCard.jsx. -
Рекомендации по именованию: Используйте PascalCase для React компонентов и camelCase для их экземпляров. eslint:
react/jsx-pascal-case// bad import reservationCard from './ReservationCard'; // good import ReservationCard from './ReservationCard'; // bad const ReservationItem = <ReservationCard />; // good const reservationItem = <ReservationCard />;
-
Имена компонентов: Используйте имя файла как имя компонента. Как пример,
ReservationCard.jsxдолжен содержать компонент с именемReservationCard. Однако для корневых компонентов директории используйте имя файлаindex.jsxи используйте имя директории как имя компонента:// bad import Footer from './Footer/Footer'; // bad import Footer from './Footer/index'; // good import Footer from './Footer';
-
Higher-order Component Naming: Use a composite of the higher-order component's name and the passed-in component's name as the
displayNameon the generated component. For example, the higher-order componentwithFoo(), when passed a componentBarshould produce a component with adisplayNameofwithFoo(Bar).
Why? A component's
displayNamemay be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening.
```jsx
// bad
export default function withFoo(WrappedComponent) {
return function WithFoo(props) {
return <WrappedComponent {...props} foo />;
}
}
// good
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;
}
```
- Названия свойств: Не используйте стандартные свойства DOM компонентов не по назначению.
Почему? Разработчики ожидают от свойств
styleиclassNameопределенного поведения. Меняя стандартное поведение вы делаете код менее читаемым, а так же повышаете вероятность возникновения ошибок.
```jsx
// bad
<MyComponent style="fancy" />
// good
<MyComponent variant="fancy" />
```
-
Не используйте
displayNameдля именования компонентов. Вместо этого этого используйте ссылку на компонент.// bad export default React.createClass({ displayName: 'ReservationCard', // stuff goes here }); // good export default class ReservationCard extends React.Component { }
-
Используйте следующий стиль отступов в JSX синтаксисе. eslint:
react/jsx-closing-bracket-location// bad <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // good <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // Если свойства помещиются в одну строку <Foo bar="bar" /> // Дочерние компоненты используют стандартные отступы <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
- Всегда используйте двойные кавычки (
") для JSX атрибутов, а одинарные (') для всего остального в JS. eslint:jsx-quotes
Почему? Стандартные HTML всегда пишутся в двойных кавычках вместо одинырных, следовательно JSX атрибуты должны следовать этому правилу.
```jsx
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
```
-
Всегда добавляйте один пробел в конец самозакрывающегося компонента. eslint:
no-multi-spaces,react/jsx-space-before-closing// bad <Foo/> // very bad <Foo /> // bad <Foo /> // good <Foo />
-
Не добавляйте пробелы между фигурными скобками в JSX атрибуты. eslint:
react/jsx-curly-spacing// bad <Foo bar={ baz } /> // good <Foo bar={baz} />
-
Всегда используйте нотацию camelCase в именах свойств.
// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} />
-
Не указывайте значение свойства явно, если оно равно
true. eslint:react/jsx-boolean-value// bad <Foo hidden={true} /> // good <Foo hidden />
-
Всегда добавляйте свойство
altв тэги<img>. Если изображение является частью интерфейса, тоaltможет быть пустым или<img>должен содержатьrole="presentation". eslint:jsx-a11y/img-has-alt// bad <img src="hello.jpg" /> // good <img src="hello.jpg" alt="Me waving hello" /> // good <img src="hello.jpg" alt="" /> // good <img src="hello.jpg" role="presentation" />
-
Не используйте такие слова, как "image", "photo" или "picture" в атрибуте
altтега<img>. eslint:jsx-a11y/img-redundant-alt
Почему? На экран пользователя элемент
imgвсегда будет выводиться как изображение, соответственно нет смысла писать об этом в атрибудет alt.
```jsx
// bad
<img src="hello.jpg" alt="Picture of me waving hello" />
// good
<img src="hello.jpg" alt="Me waving hello" />
```
-
Используйте валидные и не абстрактные значения атрбута role ARIA roles. eslint:
jsx-a11y/aria-role// bad - not an ARIA role <div role="datepicker" /> // bad - abstract ARIA role <div role="range" /> // good <div role="button" />
-
Do not use
accessKeyon elements. eslint:jsx-a11y/no-access-key
Почему? Это осложняет взаимодействие людям, использующим экранную клавиатуру.
// bad
<div accessKey="h" />
// good
<div />- Старайтесь не использовать порядковый номер элемента как свойство
key, всегда, лучше использовать ID. (why?)
// bad
{todos.map((todo, index) =>
<Todo
{...todo}
key={index}
/>
)}
// good
{todos.map(todo => (
<Todo
{...todo}
key={todo.id}
/>
))}- Всегда определяйте defaultProps для необязательных свойств компонента.
Почему? propTypes используется в качестве документации, and providing defaultProps means the reader of your code doesn’t have to assume as much. In addition, it can mean that your code can omit certain type checks.
// bad
function SFC({ foo, bar, children }) {
return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
children: PropTypes.node,
};
// good
function SFC({ foo, bar }) {
return <div>{foo}{bar}</div>;
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
};
SFC.defaultProps = {
bar: '',
children: null,
};-
Всегда используйте коллбэки в качестве refs. eslint:
react/no-string-refs// bad <Foo ref="myRef" /> // good <Foo ref={(ref) => { this.myRef = ref; }} />
-
Оборачивайте JSX тэги в круглые скобки, если они состоят более чем из одной строки. eslint:
react/wrap-multilines// bad render() { return <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent>; } // good render() { return ( <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent> ); } // good, when single line render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
-
Всегда ипшите самозакрывающиеся тэгши, если они не содержат дочерних элементов. eslint:
react/self-closing-comp// bad <Foo className="stuff"></Foo> // good <Foo className="stuff" />
-
Нсли вы пишете свойства компонента на нескольких строках, то пререносите закрывающую часть тэга на новую строку. eslint:
react/jsx-closing-bracket-location// bad <Foo bar="bar" baz="baz" /> // good <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> ); }
-
Определяйте контекст обработчиков событий в конструкторе компонента. eslint:
react/jsx-no-bind
Почему? Определение контекста в методе render приведет к созданию нового экземпляра функуии при каждой отрисовке компонента.
```jsx
// bad
class extends React.Component {
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv.bind(this)} />
}
}
// good
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv} />
}
}
```
- Не используйте нижнее подчеркивание в начале названия внутренних методов React компонента.
Why? Нижнее подчеркивание используется в некоторых языках для обозначения метода как приватного. Но, в отличие от этих языков, JavaScript, не поддерживает приватные свойства и методы. все они являются публичными. See issues #1024, and #490 for a more in-depth discussion.
```jsx
// bad
React.createClass({
_onClickSubmit() {
// do stuff
},
// other stuff
});
// good
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
}
```
-
Обязательно возвращайте значение в методе
render. eslint:react/require-render-return// bad render() { (<div />); } // good render() { return (<div />); }
- Сортирвка для
class extends React.Component:
- необязательные
staticметоды constructorgetChildContextcomponentWillMountcomponentDidMountcomponentWillReceivePropsshouldComponentUpdatecomponentWillUpdatecomponentDidUpdatecomponentWillUnmount- clickHandlers или eventHandlers такие как
onClickSubmit()илиonChangeDescription() - геттеры для метода
renderтакие какgetSelectReason()илиgetFooterContent() - необязательные методы отрисовки как
renderNavigation()илиrenderProfilePicture() render
-
Как определять
propTypes,defaultProps,contextTypes, etc...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
displayNamepropTypescontextTypeschildContextTypesmixinsstaticsdefaultPropsgetDefaultPropsgetInitialStategetChildContextcomponentWillMountcomponentDidMountcomponentWillReceivePropsshouldComponentUpdatecomponentWillUpdatecomponentDidUpdatecomponentWillUnmount- clickHandlers или eventHandlers like
onClickSubmit()илиonChangeDescription() - геттеры для метода
renderlikegetSelectReason()илиgetFooterContent() - необязательные методы отрисовки like
renderNavigation()илиrenderProfilePicture() render
- Не используйте
isMounted. eslint:react/no-is-mounted
Почему?
isMountedis an anti-pattern, это свойство не поддерживается в ES6 классах, и все идет к тому, что оно будет официально осуждаться.
Этот JSX/React стайлгайд на других языках:
Chinese (Simplified): JasonBoy/javascript
Polish: pietraszekl/javascript
Korean: apple77y/javascript
Portuguese: ronal2do/javascript
Japanese: mitsuruog/javascript-style-guide
Español: agrcrobles/javascript