Пару слов о стилизации React компонентов

от автора

Стилизация. Довольно насущный для меня момент. Несмотря на годы работы с React, стартуя новый проект, я каждый раз задумываюсь о стилизации. Я перепробовал многие её способы, больше и дольше всего я работал с css-modules и styled-components. Сегодня я хочу предложить вам рассмотреть еще один не менее интересный вариант.

Для начала я хочу вкратце пробежаться по вышеупомянутым приёмам, чтобы объяснить, что именно меня в них не устраивает, и почему я придумал еще один тысячапервый стандарт.

CSS-modules

Просто, чётко, интуитивно понятно. Никаких проблем с пересечением стилей.

import styles from './component.css'  function Component() {     return <div className={styles.root}>...</div> }

Всё вроде бы хорошо и красиво, но только на небольших простых компонентах. В более суровых условиях нас настигает куча лапши при создании сложных className-ов.

import styles from './component.css'  function Component(props) {     let className = styles.root      if (props.red) className += ' ' + styles.red      return <div className={className}>...</div> }

Да, есть конечно библиотеки типа classnames, призванные решить эту проблему…

import cn from 'classnames' import styles from './component.css'  function Component(props) {     const className = cn(styles.root, props.red && styles.red)      return <div className={className}>...</div> }

но даже тут постоянный бойлерплейт вида className={cn(...)} начинает порядком раздражать, хочется чего-то более локаничного.

Styled components

Ммм, няшка… Был момент, когда я так сильно обрадовался этой находке, что незамедлительно переписал один большой проект на новый лад.

const Root = styled.div`     color: white; `  function Component() {     return <Root>...</Root> }

Вроде, и код поопрятнее, и подход посвежее. Стилизованные компоненты можно в отдельный файл вынести, чтоб в файле основного компонента глаза не мозолили.

Но! Розовые очки рано или поздно испаряются и та же лапша, только уже под новым соусом, снова начинает раздражать.

const Root = styled.div`     color: white;      ${(props) =>         props.red &&         css`             background-color: red;         `} `  function Component(props) {     return <Root red={props.red}>...</Root> }

Добавим сюда постоянную нагрузку на генератор оригинальных названий для компонентов (тот, что в черепной коробке), а также излишнее абстрагирование в виде сокрытия реальных названий html-тегов за выдуманными псевдонимами.

Не один год я использовал этот подход и всё же пришёл к выводу, что во первых — я хочу писать css-код в родных ему css-файлах, во вторых — я хочу видеть в компонентах привычную html-разметку из привычных html-тегов.

Candy

Скажу сразу — это proposal. Чисто по опыту — велосипедостроение часто оборачивается пустой, никому не нужной тратой времени. Поэтому в этот раз я набросал рабочий вариант и, прежде чем пилить в сторону production-ready, решил прощупать почву этой статьёй.

Идея очень проста. Мы пишем привычный css, sass, less, вот прям как по кайфу 🙂

/* styles.css */  .root {     color: white; }  .red {     backgroung-color: red; }

А затем импортируем из файла стилей компоненты-html-теги, которые имеют булевы свойства связанные с названиями css-классов.

import { Div } from './styles.css'  function Component(props) {     return (         <Div root red={props.red}>             ...         </Div>     ) }

А выполнить такой финт нам позволяет webpack-загрузчик candy-loader.

Вот это поворот 🙂

Мы получаем возможноть писать привычный css и не менее привычный html, с той лишь разницей, что теги пишутся с большой буквы и расширены дополнительным набором свойств, из которых под капотом генерируется свойство className.

Импортировать можно любой стандартный html-тег. Названия классов на выходе формируются как в css-modules, т.е. одноименные классы из разных источников не будут пересекаться.

Можно подключать css-файлы, получая доступ к их стилям.

/* styles.css */ @import 'grid.css';  /*...*/

import { Div } from './styles.css'  function Component(props) {     return (         <Div root red={props.red} col_xs_12 col_sm_8>             ...         </Div>     ) }

Настройка

candy-loader базируется на postcss, поэтому для дополнительной настройки можно использовать стандартный конфигурационный файл

// .postcssrc.js  module.exports = {     plugins: {         autoprefixer: isProduction,     },     processOptions: {         map: isDevelopment,     }, }

Ну и конечно же Intellisense!

Для этого есть typescript-plugin-candy. Довольно простой в установке и настройке плагин, позволяющий получить автокомплит и проверку типов.

Что скажете?

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

Спасибо за потраченное время, буду рад вашим комментариям и предложениям по развитию.


ссылка на оригинал статьи https://habr.com/ru/post/655323/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *