Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.md

Airbnb React/JSX Style Guide

A mostly reasonable approach to React and JSX

Table of Contents

  1. Базовые правила
  2. Class vs React.createClass vs stateless
  3. Именование
  4. Объявление
  5. Отступы
  6. Кавычки
  7. Пробелы
  8. Props
  9. Refs
  10. Скобки
  11. Тэги
  12. Методы
  13. Сортировка
  14. isMounted

Базовые правила

  • Всегда включайте компонент в отдельный файл.
  • Всегда используйте JSX синтаксис.
  • Не используйте React.createElement в JSX файлах.

Class vs React.createClass vs stateless

  • Если у вас есть внутренний state и/или refs, предпочтительно использовать class extends React.Component а не React.createClass иначе у вас должна быть очень хорошая причина использовать примеси (mixins). eslint: react/prefer-es6-class react/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 displayName on the generated component. For example, the higher-order component withFoo(), when passed a component Bar should produce a component with a displayName of withFoo(Bar).

Why? A component's displayName may 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} />

Props

  • Всегда используйте нотацию 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 accessKey on 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

  • Всегда используйте коллбэки в качестве 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:
  1. необязательные static методы
  2. constructor
  3. getChildContext
  4. componentWillMount
  5. componentDidMount
  6. componentWillReceiveProps
  7. shouldComponentUpdate
  8. componentWillUpdate
  9. componentDidUpdate
  10. componentWillUnmount
  11. clickHandlers или eventHandlers такие как onClickSubmit() или onChangeDescription()
  12. геттеры для метода render такие как getSelectReason() или getFooterContent()
  13. необязательные методы отрисовки как renderNavigation() или renderProfilePicture()
  14. 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

  1. displayName
  2. propTypes
  3. contextTypes
  4. childContextTypes
  5. mixins
  6. statics
  7. defaultProps
  8. getDefaultProps
  9. getInitialState
  10. getChildContext
  11. componentWillMount
  12. componentDidMount
  13. componentWillReceiveProps
  14. shouldComponentUpdate
  15. componentWillUpdate
  16. componentDidUpdate
  17. componentWillUnmount
  18. clickHandlers или eventHandlers like onClickSubmit() или onChangeDescription()
  19. геттеры для метода render like getSelectReason() или getFooterContent()
  20. необязательные методы отрисовки like renderNavigation() или renderProfilePicture()
  21. render

isMounted

Почему? isMounted is an anti-pattern, это свойство не поддерживается в ES6 классах, и все идет к тому, что оно будет официально осуждаться.

Переводы

Этот JSX/React стайлгайд на других языках:

⬆ back to top