---
# System prepended metadata

title: Библиотека Styled-Components

---

# Библиотека Styled-Components

## Строки-шаблоны

Создаются наподобие обычных строк. Отличие только в кавычке:

```javascript
const age = 34;
const name = "John";
const html = '<div class="message">Hello</div>';

const message = `My name is ${name}, my age is ${age}`;
```

Принципиальная разница - возможность использовать подстановки выражений прямо в строке.

Если значение не относится к строке, то осуществляется его неявное преобразование, у объектов вызывается метод *toString()*

## Функции-теги

Позволяют модифицировать строку шаблон

```javascript
const transform = () => {
    return 'darkness my old friend'
}

const message = transform`Hello`;
```


У таких функций существуют аргументы:


```javascript
const transform = (expressions, ...substitutions) => {
    console.log(expressions, substitutions);
    return 'darkness my old friend...';
}
const name = 'Vladimir';

const message = transform`Hello dear ${name}! I'm glad to see you`;

console.log(message);
```

Аргументы функции-тега:
- массив строк, между которыми стояли подстановки *${}* в исходной строке-шаблоне
- значения, полученные в каждой из подстановок. Так как каждое из значений передаётся в отдельном аргументе, удобнее использовать оператор остатка (rest) ...

Например, с помощью функций-тегов можно преобразовать шаблон в верхний регистр:

```javascript
const uppercase = (strings, ...values) => strings
  .map((string, index) => {
    if (index > 0) {
      const lastValue = values[index - 1];
      return lastValue.toUpperCase() + string;
    }
    return string;
  })
  .join('');
  
const name = 'Илья';
const business = 'хороший человек';

const message = uppercase`Привет! меня зовут ${name} и я ${business}`;

console.log(message);
```

## CSS-in-JS, ещё раз

Данный подход позволяет хранить CSS свойства в JS объекте. Ссылка на такой объект передаётся через props *style*

```js
const labelStyle = {
    backgroundColor: 'rgba(0,0,0,.02)',
    color: 'rgba(0,0,0,.88)',
    fontSize: '14px'
}
```

В JSX:

```jsx
<label style={labelStyle}>Имя пользователя</label>
```

## Препроцессоры

При помощи препроцессоров или CSS-файла и технологии CSS Modules возможно выгрузить все классы в единый объект. Тогда стили вроде

```css
.wrapper {
    display: flex;
}
```

```css
.select {
    width: 100%;
    border: 1px solid #d9d9d9;
    border-left: none;
    border-radius: 6px;
    border-start-start-radius: 0;
    border-end-start-radius: 0;
}
```

```javascript
import S from './CurrencySelect.module.scss';
```

В JSX:

```jsx
<CurrencyDropdown class={S.select} />
```

Такой подход становится ещё более удобным при работе с библиотекой classnames

## Зачем нужен Styled Components

Позволяет более естественно представлять стили, написанные в форме CSS in JS

## Установка

npm: 

```bash
npm install --save styled-components
```

yarn: 

```bash
yarn add styled-components
```


## Базовые приёмы

Данный код создаст компонент с узлом div с указанным ниже кодом

```jsx

import styled from 'styled-components';

const Wrapper = styled.div`
    display: flex;
`;
```

После сборки проекта стили будут закреплены за элементом в виде CSS-класса.

Полученный компонент можно использовать привычным способом

```jsx
<Wrapper>
    <Label onClick={onLabelClick}>
        {label}
    </Label>
</Wrapper>
```

## Переиспользование стилей

Для переиспользования стилей и узла другого компонента, можно вызывать styled как функцию:

```js
const CurrencyDropdown = styled(Select)`
    width: 100%;
    border: 1px solid #d9d9d9;
    border-left: none;
    border-radius: 6px;
    border-start-start-radius: 0;
    border-end-start-radius: 0;
`;

```

## Использование props

На основе значений, переданных в props компонента можно динамически менять стили:

```jsx
const Button = styled.button`
  background: transparent;
  border-radius: 3px;
  border: 2px solid palevioletred;
  color: palevioletred;
  margin: 0 1em;
  padding: 0.25em 1em;

  ${props =>
    props.primary &&
    css`
      background: palevioletred;
      color: white;
    `};
```

дополнительные стили со свойствами background и color будут доступны в данном случае:

```jsx
<Button primary={true}>Click</Button>
```
## Анимация

Для анимации компонентов используется дополнительная функция *keyframes*

```js

import styled, { keyframes } from 'styled-components';
```

Далее анимация, заданная ранее через @keyframes в CSS задаётся через эту функцию:

```js
const labelKeyframes = keyframes`
    to {
        opacity: 0;
    }
`;

```

Чтобы подключить созданные ключевые кадры, необходимо их передать в исходную строку-шаблон:

```js
const Label = styled.div`
    background-color: rgba(0,0,0,.02);
    color: rgba(0,0,0,.88);
    font-size: 14px;
    padding: 0 11px;

    display: flex;
    white-space: nowrap;
    align-items: center;
    border: 1px solid #d9d9d9;
    border-radius: 6px;
    border-start-end-radius: 0;
    border-end-end-radius: 0;

    animation: ${labelKeyframes} 1s ease-in-out alternate-reverse infinite;
`;
```

## Создание тем

Для задания темы с основными параметрами (наподобие переменных в CSS или препроцессорах), используется компонент ThemeProvider. С его помощью props theme автоматически передаётся всем дочерним узлам

```jsx
// Define our button, but with the use of props.theme this time
const Button = styled.button`
  color: ${props => props.theme.fg};
  border: 2px solid ${props => props.theme.fg};
  background: ${props => props.theme.bg};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border-radius: 3px;
`;

// Define our `fg` and `bg` on the theme
const theme = {
  fg: "palevioletred",
  bg: "white"
};

// This theme swaps `fg` and `bg`
const invertTheme = ({ fg, bg }) => ({
  fg: bg,
  bg: fg
});

render(
  <ThemeProvider theme={theme}>
    <div>
      <Button>Default Theme</Button>

      <ThemeProvider theme={invertTheme}>
        <Button>Inverted Theme</Button>
      </ThemeProvider>
    </div>
  </ThemeProvider>
);
```

## Хуки

Альтернативный вариант использования темы - хуки withTheme и useTheme

withTheme возвращает новый компонент с props theme, который наподобие ThemeProvider отправляется дочерним компонентам:

```jsx
export default withTheme(MyContainerComponent)
```

Для получения информации о текущей теме, используется хук useTheme:

```jsx
import { useTheme } from 'styled-components'

const MyComponent = () => {
  const theme = useTheme()

  console.log('Current theme: ', theme)
  // ...
}
```