Зарегистрируйтесь, чтобы продолжить обучение

Обработка имён классов JS: React

Интерактивные элементы UI имеют более одного состояния отображения. Например, модальное окно может быть открыто или закрыто, а переключатель — включён или выключен. Обычно эти состояния меняют с помощью классов.

Работая напрямую с DOM, мы можем использовать classList, который содержит удобные методы для добавления и удаления классов. В React из коробки нет никаких удобств. Свойство className — это всего лишь строка, а строки неудобны для обработки:

class Button extends React.Component {
  render() {
    const { isPressed, isHovered, label } = this.props
    let btnClass = 'btn'
    if (isPressed) {
      // Приходится конкатенировать классы
      btnClass += ' btn-pressed'
    }
    else if (isHovered) {
      btnClass += ' btn-over'
    }
    return <button className={btnClass}>{label}</button>
  }
};

Для решения этой задачи создатели React рекомендуют использовать пакет classnames. Принцип его работы прост. Вместо манипулирования строчкой напрямую, мы формируем правильный объект, который уже будет преобразован в строку:

import cn from 'classnames'

class Button extends React.Component {
  render() {
    const { isPressed, isHovered, label } = this.props
    // Значение — это `true` или `false`
    // При значении `true` класс включен, при `false` — выключен
    // `'btn'` — это класс, который будет подставлен в любом случае
    const btnClass = cn('btn', {
      'btn-pressed': isPressed,
      'btn-over': !isPressed && isHovered,
    })
    return <button className={btnClass}>{label}</button>
  }
};

Подставим конкретные значения:

const btnClass = cn('btn', {
  'btn-pressed': false,
  'btn-over': true,
})

console.log(btnClass) // 'btn btn-over'

Функция cn() принимает на вход любое количество аргументов. Если аргумент имеет строковой тип, то он считается обязательным классом. Если это объект, тогда работает логика, описанная выше:

const btnClass = cn('btn', 'another-class', {
  'btn-pressed': isPressed,
  'btn-over': !isPressed && isHovered,
})

Обязательные классы можно задавать и в самом объекте:

const btnClass = cn({
  'btn something-else': true,
  'btn-pressed': isPressed,
  'btn-over': !isPressed && isHovered,
})

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

const buttonType = 'primary'
const btnClass = cn('btn', `btn-${buttonType}`)
console.log(btnClass) // 'btn btn-primary'
// Или что-то похожее
// const btnClass = cn('btn', {
//   [`btn-${buttonType}`]: true
// });

Функция умеет работать с массивами. Массив можно передавать в любом параметре:

const buttonType = 'primary'
const btnClass = cn('btn', ['another-class', 'btn-primary'])
console.log(btnClass) // 'btn another-class btn-primary'
// Или
// const btnClass = cn(['btn', 'another-class', 'btn-primary']);

Дополнительные материалы

  1. classnames (документация)

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff