Компоненты решают задачу представления — как и где отобразить данные. В основном содержат вёрстку.
Все данные компоненту передаются через props
, самостоятельно компонент ничего не узнает, он глупый.
Компонент глупый, но может иметь своё состояние для реализации сложной логики отображения (рендера).
Может подписываться на пользовательские события (клик мышкой, ввод с клавиатуры...), но, обычно, не обрабатывает их,
а вызывает соответствующие функции обратного вызова из props
.
Компонент решает одну конкретную задачу. Для сложных задач используется композиция из нескольких компонент.
Компонент описывается именованной функцией в CamelCase: function ComponentName(props){}
и оборачивается в
React.memo()
для строгой зависимости от props
.
Используются Хуки.
Обязательно описывать все получаемые компонентом свойства в propsTypes
и опционально значения по умолчанию в
defaultProps
(чтобы не проверять значение в коде).
Компоненты на классах используются в исключительных случаях.
Компоненты создаются в директории /components
.
Каждый компонент в отдельной директории, имя директории соответствует названию компонента в нижнем регистре через дефис.
SomeName()
→ ./some-name
Группируются в поддиректории по назначению, чтобы проще ориентироваться в них. /components/group/some-name
Не используется реэкспорт списка компонентов. Каждый компонент импортируется отдельной инструкцией с указанием полного пути.
В директории компонента могут находиться дополнительные файлы, импортируемые самим компонентом — стили, картинки, утилиты и др.
Если составные части компонента в виде отдельных компонент повторно нигде не используются, то их лучше разместить в поддиректории основного компонента.
Признак толстого компонента — большой перечень свойств в 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);