Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.md

Руководство по написанию React/JSX кода от Airbnb

Наиболее разумный подход к написанию React и JSX

Оглавление

  1. Основные правила
  2. Class против React.createClass против компонента без состояния (stateless)
  3. Примеси (mixins)
  4. Именование
  5. Объявление
  6. Выравнивание
  7. Кавычки
  8. Пробелы
  9. Свойства (Props)
  10. Ссылки (Refs)
  11. Круглые скобки
  12. Теги
  13. Методы
  14. Последовательность
  15. isMounted
  16. Переводы
  • Включайте только один React компонент в файл.
  • Всегда используйте 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>;
    }

Почему? Примеcи вносят неявные зависимости, становятся причиной конфликтов имен и быстрого роста сложностей. Для большинства случаев, в которых используются примеси, можно более эффективно применить компоненты, компоненты высшего порядка или вспомогательные модули.

  • Расширения: Используйте расширение .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';
  • Именование компонента высшего порядка: Используйте сочетание имени компонента высшего порядка и имени переданного в него компонента как свойство displayName сгенерированного компонента. Например, из компонента высшего порядка withFoo(), которому передан компонент Bar, должен получаться компонент с displayName равным withFoo(Bar).

Почему? Свойство displayName может использоваться в инструментах разработчика или сообщениях об ошибках, и если оно ясно выражает связь между компонентами, это помогает понять, что происходит.

```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;
}
```
  • Названия свойств: Избегайте использования названий свойств 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/>
    
    // very bad
    <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") в свойстве alt тега <img>. 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 роли. eslint: jsx-a11y/aria-role

    // плохо - не ARIA роль
    <div role="datepicker" />
    
    // плохо - асбтрактная ARIA роль
    <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 для всех свойств, которые не указаны как необходимые.

Почему? 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,
  children: PropTypes.node,
};
SFC.defaultProps = {
  bar: '',
  children: null,
};
  • Всегда используйте функции обратного вызова. eslint: react/no-string-refs

    // плохо
    <Foo
      ref="myRef"
    />
    
    // хорошо
    <Foo
      ref={(ref) => { this.myRef = ref; }}
    />
  • Оборачивайте в скобки JSX теги, когда они занимают больше одной строки. eslint: react/jsx-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:
  1. произвольные static методы
  2. constructor
  3. getChildContext
  4. componentWillMount
  5. componentDidMount
  6. componentWillReceiveProps
  7. shouldComponentUpdate
  8. componentWillUpdate
  9. componentDidUpdate
  10. componentWillUnmount
  11. обработчики кликов или событий, такие как onClickSubmit() или onChangeDescription()
  12. getter методы для render, такие как getSelectReason() или getFooterContent()
  13. произвольные render методы, такие как renderNavigation() или renderProfilePicture()
  14. 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

  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. обработчики кликов или событий, такие как onClickSubmit() или onChangeDescription()
  19. getter методы для render, такие как getSelectReason() или getFooterContent()
  20. произвольные render методы, такие как renderNavigation() или renderProfilePicture()
  21. render

isMounted

Почему? isMounted — это антипаттерн, который недоступен при использовании ES6 классов и который планируют официально признать устаревшим.

Это JSX/React руководство также доступно и на других языках:

⬆ к оглавлению