Углубленный взгляд на мощь стилизованных компонентов

Мое путешествие

Как и многие, я сначала начал стилизовать React с помощью встроенного CSS. Это была корректировка из таблиц стилей, но мне очень понравилась возможность определять локализованные стили и использовать возможности Javascript. Конечно, были проблемы, такие как производительность и отсутствие поддержки псевдоселекторов, но в целом меня это устраивало, и не было никаких веских причин или недостатков для поиска другого способа стилизации моих компонентов.

Когда я впервые познакомился с Стилизованными компонентами, я немного опасался преимуществ, поскольку так долго привык к встроенному CSS. В конце концов, документация React (в то время) все еще использовала встроенный CSS для всех своих примеров. Создавая прототип фреймворка, я обнаружил лучшее из обоих миров между встроенным CSS и традиционными таблицами стилей.

Стилизованные компоненты

Несмотря на то, что стилизованные компоненты определяются по-разному, они действуют в основном как компоненты React. Оба они принимают props как входной и выходной HTML.

Давайте возьмем этот образец компонента кнопки, стилизованного аналогично кнопкам Bootstrap со стилизованными компонентами.

import styled from 'styled-components';
const Button = styled.button`
  display: inline-block;
  padding: 6px 12px;
  font-size: 16px;
  font-family: Arial, sans-serif;
  line-height: 1.5;
  color: white;
  background-color: #6c757d;
  border: none;
  border-radius: 4px;
  :not(:disabled) {
    cursor: pointer;
  }
  :hover {
    background-color: #5a6268;
  }
`;

Фабрика компонентов styled импортируется и используется для создания кнопки со стилями с использованием литерала шаблона (`...`). Эта фабрика поддерживает все допустимые элементы HTML, будь то div, h1, p и т. Д. Точно так же стили в литерале шаблона принимают весь допустимый CSS, так что вы можете сходить с ума со сложными селекторами CSS.

использование

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

const App = () => {
  return (
    <Button onClick={() => alert('clicked!')} type="button">
      Button
    </Button>
  );
};

Как и компоненты React, стилизованные компоненты также принимают реквизиты и определяются точно так же. Стилизованные компоненты передают все (действительные) свойства DOM в DOM.

Внутренности

Хорошо, а как это работает? Какой волшебный процесс происходит внутри?

  1. При рендеринге стилизованные компоненты будут генерировать уникальное имя класса на основе определенных стилей.
  2. Стилизованные компоненты будут вставлять тег стиля (<style>) в заголовок HTML, сопоставляя уникальное имя класса с определенными стилями.
  3. Стилизованные компоненты будут отображать элемент с уникальным именем класса.

Эти шаги приведут к тому, что структура DOM для нашего примера будет выглядеть так.

<!DOCTYPE html>
<html lang="en">
  <head>
    <style data-styled="active" data-styled-version="5.2.0">
      .bAeiQF {
          display: inline-block;
          padding: 6px 12px;
          font-size: 16px;
          font-family: Arial, sans-serif;
          line-height: 1.5;
          color: white;
          background-color: #6c757d;
          border: none;
          border-radius: 4px;
      }
      .bAeiQF:not(:disabled) {
          cursor: pointer;
      }
      .bAeiQF:hover {
          background-color: #5a6268;
      }
    </style>
  </head>
  <body>
  <div id="root">
    <button type="button" class="sc-bdnylx bPvsWA">
      Button
    </button>
  </div>
  </body>
</html>

Расширение компонентов

Фабрику компонентов styled также можно использовать для расширения существующих стилей. Он может принимать стилизованный компонент и возвращать новый в манере, напоминающей компоненты высшего порядка React.

const PrimaryButton = styled(Button)`
  background-color: #007bff;
  :hover {
    background-color: #0069d9;
  }
`;
const App = () => {
  return (
    <PrimaryButton onClick={() => alert('clicked!')} type="button">
      Primary
    </Button>
  );
};

Использование styled в качестве функции приведет к созданию нового стилизованного компонента, который имеет стили из компонента Button и новые стили, определенные в литерале шаблона. Если стили конфликтуют, новые стили будут иметь приоритет. Все свойства (кроме тех, которые имеют префиксы $; см. Параметры стиля) также будут переданы нижестоящему компоненту.

Точно так же фабрика компонентов styled может расширять компоненты React с небольшими изменениями.

const ButtonComponent = ({ className }) => {
  return (
    <Button
      className={className}
      onClick={() => alert('clicked!')}
      type="button"
    >
      Primary
    </Button>
  );
};
const PrimaryButton = styled(ButtonComponent)`
  background-color: #007bff;
  :hover {
    background-color: #0069d9;
  }
`;

Единственное ключевое дополнительное дополнение, которое позволяет это сделать, - это опора className. Расширенный стилизованный компонент установит className и передаст его компоненту React при рендеринге. Этот className будет соответствовать определенному стилю точно так же, как он работает со стилизованными компонентами. Таким образом, без className стиль применяться не будет.

Составные стили

Стилизованные компоненты также позволяют нам определять многократно используемые стили, которые можно объединить в стилизованные компоненты.

import styled, { css } from 'styled-components';
const blackFont = css`
  color: black;
`;
const WarningButton = styled(Button)`
  background-color: #ffc107;
  :hover {
    background-color: #e0a800;
  }
  ${blackFont}
`;
const App = () => {
  return (
    <WarningButton onClick={() => alert('clicked!')} type="button">
      Warning
    </WarningButton>
  );
};

Здесь blackFont - это общий стиль. Он определяется с помощью литерала шаблона с помощью помощника css. WarningButton и любые другие стилизованные компоненты могут включать этот стиль с синтаксисом фигурных скобок со знаком доллара для объединения двух литералов шаблона.

Реквизит для укладки

Кроме того, сами стилизованные компоненты могут использовать реквизиты для изменения стиля.

import styled, { css } from 'styled-components';
const SuccessButton = styled(Button)`
  ${props =>
    props.$success
      ? css`
          background-color: #28a745;
          :hover {
            background-color: #218838;
          }
        `
      : ''}
`;
const App = () => {
  return (
    <SuccessButton
      $success
      onClick={() => alert('clicked!')}
      type="button"
    >
        Success
    </SuccessButton>
  );
};

Здесь компонент Button расширен и принимает свойство $success, которое условно устанавливает стили успеха (используя составной стиль), если установлено значение true.

Хотя реквизитам для стилизации не нужен префикс $, я настоятельно рекомендую его. Обычно все свойства передаются базовому компоненту (элементу DOM, компоненту React или компоненту со стилем). Свойства с именами с префиксом $, называемые временными реквизитами, используются только определенным стилизованным компонентом и не передаются нижестоящему компоненту. Это делает кристально ясным, какие реквизиты предназначены для стилизации, а какие - для нижележащего компонента.

Последние мысли

Стилизованные компоненты обеспечивают простой и фантастический интерфейс для стилизации. Он расширяет возможности разработчика для CSS, используя основные принципы React. Он настолько хорошо интегрируется с React, что я не могу не задаться вопросом, почему React не просто интегрирует его изначально - это просто так хорошо. Я никогда не вернусь к своим старым способам укладки.

Ресурсы