React Junior
208 subscribers
37 photos
462 links
Изучение React с нуля
加入频道
JSS плагины

Сразу же видны некоторые неудобства. Например, хотелось бы писать имена css-свойств в camelCase, но из коробки jss такое не позволяет.

Для этого есть разные плагины. Например, jss-plugin-camel-case.

Подключить плагин можно с помощью метода jss.use() - теперь можно писать свойства так, как удобно.

https://codesandbox.io/s/jss-plugins-react-junior-qp23m

Есть и другие полезные плагины (официальные). Например, jss-plugin-default-unit позволяет не указывать единицы измерения, а jss-plugin-vendor-prefixes добавляет вендорные префиксы к свойствам.

Важно: порядок перечисления плагинов в методе jss.use() имеет значение.

Список официальных плагинов (в правильном порядке): https://cssinjs.org/plugins?v=v10.9.0

Пресет по умолчанию

Можно не подключать плагины по одному, а сразу установить набор плагинов (пресет): jss-preset-default. Он включает больше десятка разных (официальных) плагинов (посмотреть можно здесь https://github.com/cssinjs/jss/blob/master/packages/jss-preset-default/package.json#L37-L48).

Для его установки используется метод jss.setup().

https://codesandbox.io/s/jss-preset-react-junior-fu5rg?file=/src/index.js

#документация #стили #jss #примерыкода
Официальные плагины JSS

👉 jss-plugin-rule-value-function (входит в jss-preset-default)

Использование функций в качестве значений, для указания динамических стилей.

👉 jss-plugin-rule-value-observable (входит в jss-preset-default)

Использование TC39 Observables https://github.com/tc39/proposal-observable для динамических анимаций.

👉 jss-plugin-template (входит в jss-preset-default)

Использование шаблонных строк.

👉 jss-plugin-cache

Кеширование правил по ссылке для лучшей производительности.

👉 jss-plugin-global (входит в jss-preset-default)

Глобальные стили.

👉 jss-plugin-extend (входит в jss-preset-default)

Расширение наборов правил (наследование в некотором роде).

👉 jss-plugin-nested (входит в jss-preset-default)

Вложенные селектор и псевдоселекторы.

👉 jss-plugin-compose (входит в jss-preset-default)

Добавление к сгенерированному классу дополнительных классов, например, дла использования с CSS-фреймворками.

👉 jss-plugin-camel-case (входит в jss-preset-default)

Возможность указывать имена свойств в camelCase.

👉 jss-plugin-default-unit (входит в jss-preset-default)

Возможность не указывать единицы измерения для числовых значений.

👉 jss-plugin-expand (входит в jss-preset-default)

Разделение составных свойств на простые (border-color, border-width, border-style).

👉 jss-plugin-vendor-prefixer (входит в jss-preset-default)

Добавление вендорных префиксов.

👉 jss-plugin-props-sort (входит в jss-preset-default)

Сортировка свойств по алфавиту.

👉 jss-plugin-isolate

Изоляция правил через автоматический сброс свойств.

Большинство плагинов принимает разные опции для настройки (подробнее - в документации).

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

#документация #стили #jss
Манипуляции с созданными стилями

Получив таблицу стилей из метода createStyleSheet, мы можем ее изменять, например, добавлять, заменять или удалять правила.

👉 sheet.addRule(selector, style, options)
👉 sheet.addRules(styles)
👉 sheet.replaceRule(selector, style, options)
👉 sheet.deleteRule(name)

Подробнее об этих методах и их параметрах - в документации: https://cssinjs.org/jss-api?v=v10.9.0#add-a-rule-to-an-existing-style-sheet

#документация #стили #jss
Функциональные значения в JSS

Один из официальных плагинов (jss-plugin-rule-value-function) позволяет использовать функции в качестве значений свойств, чтобы получить динамически изменяющиеся стили.

Но если просто указать функцию, ничего не произойдет. Чтобы она выполнилась, нужно вызвать метод sheet.update(data), в котором можно передать объект с данными. Этот объект попадет в функцию в качестве параметра, и из него можно брать данные для вычисления значения свойства.

Это в какой-то мере поддержка тем оформления.

Чтобы обновлять стили уже после того, как они добавлены в DOM (sheet.attach()), нужно связать созданный объект стилей и настоящую таблицу в DOM. Для этого при создании (jss.createStyleSheet(styles, options)) нужно передать во втором параметре настройку link: true.

https://codesandbox.io/s/jss-functional-values-react-junior-dqq0b?file=/src/index.js

#документация #стили #jss #примерыкода
Синтаксис JSS

И перед тем, как мы перейдем непосредственно к React JSS, краткий обзор синтаксиса. Посмотрим, как оформляются медиа-запросы, анимации и прочие интересные моменты.

Медиа-запросы

Указываются как отдельное свойство объекта:

const styles = {
button: {
width: 100
},
'@media (min-width: 1024px)': {
button: {
width: 200
}
}
}


Интерполяция

Так как стили указываются в виде обычных JS-объектов, то можно пользоваться всеми их возможностями, например, динамическими именами свойств:

const minWidth = 1024

const styles = {
button: {
width: 100
},
[`@media (min-width: ${minWidth}px)`]: {
button: {
width: 200
}
}
}


#документация #стили #jss #примерыкода
Синтаксис JSS. Keyframes

Анимации также задаются в отдельном свойстве объекта стилей.

const styles = {
'@keyframes slideRight': {
from: {opacity: 0},
to: {opacity: 1}
}
}


Важно помнить, что имя анимации в сгенерированной таблице стилей будет изменено, поэтому для ссылки на него нужно использовать специальную форму записи - со значком $.

const styles = {
// ...
container: {
animationName: '$slideRight'
}
}


#документация #стили #jss #примерыкода
Синтаксис JSS. Фоллбэки

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

В JSS это делается вот так:

const styles = {
container: {
background: 'linear-gradient(to right, red 0%, green 100%)',
fallbacks: {
background: 'red'
}
}
}


Сгенерированный код:

.container-0 {
background: red;
background: linear-gradient(to right, red 0%, green 100%);
}


Если нужно несколько фоллбэков, их можно указать в массиве:

const styles = {
container: {
display: 'flex',
fallbacks: [{display: 'box'}, {display: 'flex-box'}]
}
}


#документация #стили #jss #примерыкода
Синтаксис JSS. Font Face

По аналогии с медиа-запросами, правило @font-face указывается в отдельном свойстве объекта стилей:

const styles = {
'@font-face': {
fontFamily: 'MyWebFont',
src: 'url(webfont.eot)'
}
}


Или в виде массива, если шрифтов несколько:

const styles = {
'@font-face': [
{
fontFamily: 'MyWebFont',
src: 'url(webfont.eot)'
},
{
fontFamily: 'MySecondFont',
src: 'url(webfont2.eot)'
}
]
}


Вообще все @-правила указываются подобным образом:

const styles = {
'@charset': '"utf-8"',
'@import': 'url(http://mysite.com/custom.css)',
'@namespace': 'url(http://mysite.com/xhtml)'
}


#документация #стили #jss #примерыкода
Синтаксис JSS. Сложные значения

Если нужно задать какому-то свойству несколько значений, например, несколько фоновых изображений, в обычном CSS мы обычно разделяем их запятой.

Если мы используем короткий вариант свойства, например, margin вместо margin-top + margin-left + margin-right + margin-bottom, то отдельные значения мы разделяем пробелом.

JSS предлагает подобные конструкции оформлять в виде массивов:

const styles = {
button: {
margin: [5, 10]
}
}


Или даже в виде массивов массивов, если у вас несколько составных значений:

const styles = {
button: {
background: [
['url(image1.png)', 'no-repeat', 'top'],
['url(image1.png)', 'no-repeat', 'right']
]
}
}


Кроме того, помним, что короткое свойство можно разбить на составляющие:

const styles = {
button: {
background: {
color: 'white',
image: 'url("/some/url/image.png")',
repeat: 'no-repeat',
position: 'contain'
}
}
}


Быстро потестировать JSS-синтаксис можно здесь: https://cssinjs.org/repl/

#документация #стили #jss #примерыкода
👍1
Синтаксис JSS

!important

Чтобы добавить к значению свойства модификатор !important, нужно использовать массивы:

const styles = {
button: {
color: [['red'], '!important'],
margin: [[5, 10], '!important']
}
}

Выглядит избыточно, так что это еще одна хорошая причина не использовать !important.

content

Если значением свойства является строка, например, как в свойстве content, ее нужно дополнительно обернуть в кавычки:

const styles = {
button: {
'&:after': {
content: '"JSS"'
}
}
}

Тут же отметим, что в качестве ссылки на элемент для вложенных селекторов псевдоэлементов используется символ &, как в SCSS.

#документация #стили #jss #примерыкода
Синтаксис JSS. CSS Гудини

JSS поддерживает API CSS Houdini:

const styles = {
button: {
margin: CSS.px(10)
}
}


Главное, не забывать про полифилл для браузеров без поддержки.

Вот здесь есть пример кода: https://codesandbox.io/s/houdini-typed-value-jmec9
А вот здесь можно почитать подробнее про CSS Houdini (рус.): https://habr.com/ru/post/494660/

#документация #стили #jss #примерыкода #ссылки
Создание универсальной UI-библиотеки

Доклад с конференции YaTalks 2021, которая проходила в начале декабря 2021: https://www.youtube.com/watch?v=0LuKoLJ3zbU

Время: 35 минут, можно смотреть на скорости 1.25.

Разработчик из Яндекса, который занимается созданием общей библиотеки компонентов (для всех сервисов Яндекс, очевидно), рассказывает о том, зачем нужен универсальный UI Kit, какие проблемы современного веба он должен решать, а главное, как же его создать.

Он предлагает выносить из компонентов всю императивную логику в хуки (весь код на React) и использовать ее декларативно.

Если у вас есть компонент Button, у которого есть состояние hover, то это состояние не нужно создавать в самом компоненте, а следует вынести в хук useHover. Из хука следует вернуть собственно флаг isHovered, а также набор атрибутов, которые нужно поместить на HTML-элемент кнопки, чтобы все заработало.

Внутри хука вы можете определить, на каком устройстве запущено приложение и какие обработчики нужно установить на элемент, чтобы отслеживать событие ховера. Такой хук затем можно переиспользовать не только для кнопок, но и для других элементов, которые могут "ховериться".

Еще более полезный хук usePressed, который отслеживает состояние "нажатия". Недостаточно поставить обработчик только на событие клика, чтобы знать, когда ваша кнопка нажата. Нужно учитывать также клавиатурные события (нажатие на Enter или Space, когда кнопка находится в фокусе), тач-события и т.д. Всю эту логику полезно инкапсулировать в хуке, из которого наружу торчит только флаг isPressed и атрибуты, которые нужно установить для HTML-элемента.

Это примеры вынесения в хук интерактивного взаимодействия. Таким же образом можно выделять состояние компонента (ToggleState - включен/выключен, SelectState - выбранный элемент из списка) или его семантику (Select, Button и т.д.) Это уже могут быть более сложные хуки, которые под капотом используют композицию более простых. Например, хук useOption представляет элемент списка и может отслеживать состояния isFocused и isSelected.

Помимо основной логики в такие хуки можно поместить всю необходимую HTML-семантику - aria-атрибуты, так что вам не придется задумываться об этом.

Отдельные хуки легче тестировать, описывать и переиспользовать.

В целом это звучит очень интересно, так как позволяет сильнее отделить логику (хук) от представления (верстка). Несмотря на то, что все примеры на React, этот подход, вероятно, можно применить и в других фреймворках, и даже в ванильном JS, но конечно с рядом условий (как минимум потребуются некие вспомогательные функции).

Репозиторий с примерами кода: https://github.com/use-platform/use-platform. Здесь уже реализованы многие хуки для интерактивности и семантики.

#ссылки #хуки #паттерны
👍1
Схема композиции хуков и пример кода до/после:
👍1😢1
JSS + React

В React-приложениях можно, конечно, использовать базовый пакет JSS, но лучше все-таки воспользоваться специальным пакетом react-jss. У него есть ряд преимуществ:

1. Дефолтный пресет плагинов уже установлен.
2. Извлекается критический CSS.
3. Создаются таблицы стилей только для смонтированных компонентов.
4. Правила, заданные в виде функций, обновляются автоматически.

https://codepen.io/furrycat/pen/xxPwmvM?editors=0010

Для создания стилей нам понадобится функция createUseStyles. Она получает стили в виде объекта и возвращает пользовательский хук (в документации он назван useStyles), который можно использовать в компонентах.

Из хука возвращается объект, содержащий сгенерированные имена классов.

Официальная песочница: https://codesandbox.io/s/j3l06yyqpw

#документация #стили #jss #примерыкода
React JSS. Динамические свойства

При использовании react-jss не нужно обновлять таблицу стилей вручную. Достаточно передать в хук данные, которые могут изменяться. При изменении этих данных стили тоже автоматически изменятся.

https://codepen.io/furrycat/pen/QWOjYjO?editors=0011

#документация #стили #jss #примерыкода
Префикс для имен классов

При необходимости можно добавить сгенерированным классам определенный префикс.

Метод createUseStyles принимает вторым параметром объект с настройками. Желаемый префикс нужно указать в поле name.

#документация #стили #jss #примерыкода
React JSS. Темы

Для поддержки тем нам потребуется готовый компонент ThemeProvider. Ему нужно передать в проп theme текущую тему (в виде объекта или функции).

Далее есть два способа использовать тему в компоненте.

Способ #1

https://codesandbox.io/s/react-jss-temy-react-junior-f6d6x?file=/src/Button1.js

Чтобы выцепить тему в компоненте, используем готовый хук useTheme. Он возвращает тему, которую мы передаем как параметр в хук useStyles вместе с остальными динамически изменяющимися данными. При изменении темы, стили тоже изменятся.

Способ #2

https://codesandbox.io/s/react-jss-temy-react-junior-f6d6x?file=/src/Button2.js

Вместо объекта стилей нужно передать в метод createUseStyles функцию. Первым параметром этой функции как раз и будет тема. Из функции нужно вернуть объект стилей.

То есть в первом случае задача по передаче темы в стили полностью лежит на компоненте, а во втором случае компонент в этом вообще не участвует.

Второй способ удобнее, если много css-свойств зависят от темы. Тогда их не придется оформлять в виде функций. А первый способ лучше выглядит, когда кроме темы стили зависят от других пропсов.

#документация #стили #jss #примерыкода
React JSS. Отдельные контексты тем

Можно создавать собственные контексты тем, с собственными провайдерами и хуками useTheme, например, чтобы избежать конфликтов разных тем.

Контекст создается с помощью функции createTheming. А потом из него уже берутся ThemeProvider и хук useTheme.

Подробнее в документации: https://cssinjs.org/react-jss?v=v10.9.0#using-custom-theming-context

#документация #стили #jss
Настройка JSS с помощью JssProvider

react-jss предоставляет компонент JssProvider, который позволяет более тонко настроить механизм работы JSS. Соответственно все настройки будут действовать для дочерних компонентов провайдера.

С помощью JssProvider, например, можно изменить функцию, которая генерирует имена классов.

Подробнее в документации: https://cssinjs.org/react-jss?v=v10.9.0#class-name-generator-options

#документация #стили #jss
Получив представление о React JSS идем дальше по списку способов стилизации React-компонентов.

Следующий в списке Radium, но честно говоря, он выглядит каким-то не очень живым.

Репозиторий: https://github.com/FormidableLabs/radium

Radium - это опенсорсная библиотека от Formidable. В репозитории указано, что она стабильна, изменения больше не вносятся. На npm довольно много скачиваний.

Разберем его коротко, для общего развития.

Компонент высшего порядка

Radium - это HOC, то есть функция, которая оборачивает ваш компонент как декоратор, добавляя к нему некоторую функциональность. В данном случае - это функциональность обработки стилей.

Стили предполагается оформлять в виде объекта, практически как в JSS, с некоторыми тонкостями.

Основная же идея здесь в том, что мы имеем дело с inline-стилями. То есть Radium не генерирует CSS, а навешивает стили прямо на элемент.

Он даже умеет эмулировать псевдоклассы :focus, :hover и :active - с помощью отслеживания событий из JavaScript. Из-за такого механизма не получится, например, эмулировать ховер из панели разработчика.

Медиа-запросы тоже поддерживаются, но с условиями. Для них как раз генерируется CSS, и нужно использовать компонент StyleRoot, чтобы вставлять его.

В целом на первый взгляд выглядит довольно проблемно: инлайновые стили, эмуляция состояний из JavaScript, не поддерживаются другие псевдоклассы, нет псевдоэлементов.

Небольшая практика: https://codesandbox.io/s/radium-react-junior-3utg2?file=/src/Button.js

#документация #стили #radium #примерыкода