Skip to content

Latest commit

 

History

History
 
 

react

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Керівництво по стилю React/JSX від Airbnb

Найбільш обгрунтований підхід до React та JSX

Зміст

  1. Основні правила
  2. Class проти React.createClass проти безстейтового компонента
  3. Іменування
  4. Оголошення
  5. Вирівнювання
  6. Лапки
  7. Пробіли
  8. Властивості - Props
  9. Посилання - Refs
  10. Дужки
  11. Теги
  12. Методи
  13. Послідовність
  14. isMounted

Основні правила

  • Включайте лише один React компонент у файл.
  • Завжди використовуйте JSX синтаксис.
  • Не використовуйте React.createElement, якщо тільки ви не ініціалізуєте програму з файлу, який не є JSX.

Class проти React.createClass проти безстейтового компоненту

  • Якщо у вас є внутрішній 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} />

Властивості (Props)

  • Завжди використовуйте 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,
};

Посилання (Refs)

  • Завжди використовуйте зворотні виклики 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:
  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 стилями також доступне іншими мовами:

⬆ вверх