FreeCode.Academy

Стратегии обучения

Уроки

Технологии

Участники

Проекты

Топики

Блоги

Офис

О проекте

Николай Ланец
Николай Ланец
5 мая 2021 г., 4:26

Пишем компоненты с параметрами в styled-components

Всем привет!

Поступил свежий вопрос, в ответ на который и пишу данный топик. Задачка довольно тривиальная, но в реализации показывает преимущество использование styled-components в связке с TypeScript.

Что было и что стало?

Было выпадающее меню, в котором стили менялись в зависимости от состояния переменной citiesOpened.
<ul className="dropdown-menu" style={{ display: citiesOpened ? 'block' : 'none', }} > {citiesList} </ul>
Что здесь не так?

1. На уровне TS здесь никак не задается, что свойство style::display обязательное.
2. Лишняя заморочка с придумыванием className, чтобы оно точно не пересеклось с какими-нибудь другими стилями (Вдруг где-то еще прописаны стили для .dropdown-menu).
3. Навозможность переиспользования кода (где-то же еще может понадобиться такое меню (хотя для этого в таком виде все равно его надо улучшать, но это уже другая история:)))

Что сделано.

На всякий случай весь коммит: https://github.com/Pivkarta/pivkarta.ru-2/pull/2/commits/0277ad2d148046b519a1c6c11923385423868628

Простые HTML-теги были заменены на styled-components.

Корневой li на вот это:
export const DropdownMenuBox = styled.li` list-style: none; margin-left: 50px; margin-top: 7px; `
А ul на вот это
export type DropdownMenu = { /** * Открыто или закрыто */ opened: boolean } export const DropdownMenu = styled.ul<DropdownMenu>` overflow: auto; position: absolute; background: #fff; list-style: none; padding-inline-start: 15px; max-height: 60vh; ${({ opened }) => { if (opened) { return css` display: block; ` } else { return css` display: none; ` } }} `
Соответственно в самом реакт-компоненте стало так:
<DropdownMenuBox> <a onClick={toggleMenuCities} title="Пивная карта по городам" > {mainCity.name} <i className="fa fa-angle-down"></i> </a> <DropdownMenu opened={citiesOpened}>{citiesList}</DropdownMenu> </DropdownMenuBox>


В чем здесь выигрыш?

1. TS будет ругаться, если обязательное свойство не указано.


2. Не надо придумывать className. Здесь мы оперируем самими компонентами и их же можно использовать для расширения стилей. Пример:
export const DropdownMenu = styled.ul<DropdownMenu>` // ... max-height: 60vh; // ... ` export const MainMenuStyled = styled.div<MainMenuStyledProps>` // ... ${DropdownMenu} { max-height: 70vh; } // ... `
Здесь я специально так сделал для наглядности, хотя в нашем случае это и не требовалось. В общем, в самом DropdownMenu указана максимальная высота 60vh, но в MainMenuStyled прописано, что вложенным компонентам DropdownMenu надо задать максимальную высоту 70vh. При этом вполне допускается и другие классические селекторы прописывать типа class, id и т.п. К примеру так:
${DropdownMenu} { max-height: 70vh; &.cities { max-height: 80vh; } }
А в реакт-компоненте прописать этот класс:
<DropdownMenu opened={citiesOpened} className="cities" >{citiesList}</DropdownMenu>

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

P.S. Я только тут свои же правила нейминга нарушил. В стилях такие компоненты надо писать с суффиксом Styled, то есть не DropdownMenu, а DropdownMenuStyled. Но это я сейчас отдельно коммит выкачу, статью уже не буду переписывать. Просто имейте это ввиду.

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