Работа с CSS модулями в React: лучшие практики и примеры

месяц назад·2 мин. на чтение

В этой статье мы рассмотрим лучшие практики работы с CSS модулями в React и представим примеры их использования.

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

Именование классов и файлов

CSS модули позволяют автоматически генерировать уникальные имена классов для каждого компонента. Чтобы сделать код более понятным и поддерживаемым, рекомендуется использовать осмысленные имена классов и файлов, отражающие их назначение. Например, если у вас есть компонент Button, вы можете назвать его стилевой файл Button.module.css.

Использование локальных и глобальных стилей

CSS модули позволяют определить локальные стили для конкретного компонента, а также использовать глобальные стили для всего приложения. Такой подход позволяет создавать переиспользуемые стили и управлять ими более эффективно. Например, вы можете определить общие стили для кнопок в глобальном файле стилей, а затем использовать локальные стили для конкретного компонента Button, если необходимы дополнительные или измененные стили.

Подключение CSS модулей в React-компонентах

Чтобы использовать CSS модули в функциональных компонентах React, вы можете импортировать стили с помощью конструкции import и применить их к элементам JSX с помощью атрибута className. Например, если у вас есть стилевой файл Button.module.css c классом button, вы можете импортировать его и применить к кнопке следующим образом:
import React from "react";
import styles from "./Button.module.css";

const Button = () => {
  return <button className={styles.button}>Click me</button>;
};

export default Button;

Использование динамических классов

CSS модули также поддерживают динамическое добавление классов в зависимости от определенных условий. Например, если вы хотите добавить класс active к кнопке, если она находится в активном состоянии, вы можете использовать стандартный оператор if/else внутри функционального компонента для определения значения атрибута className:
import React, { useState } from "react";
import styles from "./Button.module.css";

const Button = () => {
  const [isActive, setIsActive] = useState(false);

  const handleButtonClick = () => {
    setIsActive(!isActive);
  };

  return (
    <button
      className={`${styles.button} ${isActive ? styles.active : ""}`}
      onClick={handleButtonClick}
    >
      Click me
    </button>
  );
};

export default Button;

Наследование стилей

CSS модули позволяют наследовать стили других классов, что упрощает повторное использование существующих стилей. Например, вы можете определить базовый класс base с общими стилями для всех кнопок, а затем создать новый класс button с дополнительными стилями:
/* Button.module.css */

.base {
  /* общие стили для всех кнопок */
}

.button {
  composes: base;
  /* дополнительные стили для кнопок */
}
Это позволяет создавать более модульные и гибкие стили, а также упрощает их поддержку и изменение. В заключение, работа с CSS модулями в React выгодна для разработки функциональных компонентов, так как позволяет организовать и изолировать стили для каждого компонента. Надеюсь, эти лучшие практики и примеры помогут вам эффективно использовать CSS модули в ваших проектах.

React паттерн headless component

месяц назад·2 мин. на чтение

Рассмотрим использование паттерна headless component для создания модульных и гибких компонентов в React приложениях.

Разработка программного обеспечения — это непрерывный процесс. Самой большой проблемой в этом процессе является удобство сопровождения. Когда новые функции и улучшения начинают добавляться, это приводит к добавлению большего количества кода. В этой статье мы рассмотрим простой паттерн в React, который позволяет создавать компоненты, ориентированные на будущее. Цель состоит в том, чтобы эти компоненты легко адаптировались к будущим изменениям, сохраняя при этом бизнес-логику отдельно от кода пользовательского интерфейса.

Как это работает?

Суть этого шаблона заключается в том, чтобы отделить бизнес-логику от UI части самого компонента. Когда в будущем потребуется обновить пользовательский интерфейс, это можно сделать, не затрагивая код бизнес-логики. Паттерн, который мы собираемся использовать, называется headless component. В этом шаблоне компонент реализован в виде хуков React. Этот компонент отвечает за логику и управление состоянием. Headless-компонент ничего не знает о пользовательском интерфейсе. Создается отдельный компонент, который отвечает только за пользовательский интерфейс. Паттерн используется многими популярными библиотеками компонентов React, такими как: DownShift, React Table и т.д.

Ваш первый headless компонент

Начнем с написания первого React компонента с использованием этого шаблона. Ниже приведен пример компонента dropdown:
const useDropdown = (items: Item[]) => {
  // состояние
  const [selectedIndex, setSelectedIndex] = useState<number>(-1);
  const [isOpen, setIsOpen] = useState(false);
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);

  // функция возвращающая aria-атрибуты для UI
  const getAriaAttributes = () => ({
    role: "combobox",
    "aria-expanded": isOpen,
    "aria-activedescendant": selectedItem ? selectedItem.text : undefined,
  });

  const handleKeyDown = (e: React.KeyboardEvent) => {
    // реализация на основе switch-case
  };
  
  const toggleDropdown = () => setIsOpen((isOpen) => !isOpen);

  return {
    isOpen,
    toggleDropdown,
    handleKeyDown,
    selectedItem,
    setSelectedItem,
    selectedIndex,
  };
};
Давайте интегрируем наш headless-компонент с компонентом, отвечающим за обработку пользовательского интерфейса:
const Dropdown = ({ items }: DropdownProps) => {
  const {
    isOpen,
    selectedItem,
    selectedIndex,
    toggleDropdown,
    handleKeyDown,
    setSelectedItem,
  } = useDropdown(items);

  return (
    <div className="dropdown" onKeyDown={handleKeyDown}>
      <Trigger
        onClick={toggleDropdown}
        label={selectedItem ? selectedItem.text : "Select an item..."}
      />
      {isOpen && (
        <DropdownMenu
          items={items}
          onItemClick={setSelectedItem}
          selectedIndex={selectedIndex}
        />
      )}
    </div>
  );
};
Выше приведен очень простой пример компонента. Представьте себе возможность, когда один и тот же шаблон интегрируется с более сложными приложениями. Шаблон headless component является чрезвычайно мощным, когда речь идет о создании перспективных компонентов с высокой степенью расширяемости.

Когда использовать этот шаблон?

Преимущество этого шаблона раскрывается при создании большого приложения, которое часто меняется. Реализация этого шаблона не только превращает компоненты React в расширяемые, но и делает их очень удобными в сопровождении в большой кодовой базе.