Компоненты

  1. Компоненты решают задачу представления — как и где отобразить данные. В основном содержат вёрстку.

  2. Все данные компоненту передаются через props, самостоятельно компонент ничего не узнает, он глупый.

  3. Компонент глупый, но может иметь своё состояние для реализации сложной логики отображения (рендера).

  4. Может подписываться на пользовательские события (клик мышкой, ввод с клавиатуры...), но, обычно, не обрабатывает их, а вызывает соответствующие функции обратного вызова из props.

  5. Компонент решает одну конкретную задачу. Для сложных задач используется композиция из нескольких компонент.

  6. Компонент описывается именованной функцией в CamelCase: function ComponentName(props){} и оборачивается в React.memo() для строгой зависимости от props.

  7. Используются Хуки.

  8. Обязательно описывать все получаемые компонентом свойства в propsTypes и опционально значения по умолчанию в defaultProps (чтобы не проверять значение в коде).

  9. Компоненты на классах используются в исключительных случаях.

  10. Компоненты создаются в директории /components.

  11. Каждый компонент в отдельной директории, имя директории соответствует названию компонента в нижнем регистре через дефис. SomeName()./some-name

  12. Группируются в поддиректории по назначению, чтобы проще ориентироваться в них. /components/group/some-name

  13. Не используется реэкспорт списка компонентов. Каждый компонент импортируется отдельной инструкцией с указанием полного пути.

  14. В директории компонента могут находиться дополнительные файлы, импортируемые самим компонентом — стили, картинки, утилиты и др.

  15. Если составные части компонента в виде отдельных компонент повторно нигде не используются, то их лучше разместить в поддиректории основного компонента.

  16. Признак толстого компонента — большой перечень свойств в props или вёрстка на сотню строк.

Типовая структура компонента

component-name 
├── index.js
└── style.less

Пример кнопки с функцией обратного вызова на клик

function Button(props) {
  // Все колбэки группируются в объекте callbacks - ниже по коду знаем от куда функция
  const callbacks = {
    onClick: useCallback(e => {
      if (props.onClick) {
        e.preventDefault();
        props.onClick();
      }
    }, [props.onClick]),
  };
  // props не разворачивается на отдельные переменные, чтобы сразу и однозначно понимать от куда берутся значения
  return (
    <button
      type={props.type}
      className={themes('Button', props.theme)}
      disabled={props.disabled}
      title={props.title}
      onClick={callbacks.onClick}
    >
      {props.children}
    </button>
  );
}

Button.propTypes = {
  children: PropTypes.node,
  onClick: PropTypes.func,
  type: PropTypes.string,
  title: PropTypes.string,
  theme: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
  disabled: PropTypes.bool,
};

Button.defaultProps = {
  type: 'button',
  disabled: false,
  theme: '',
};

export default React.memo(Button);