Одиночные и множественные значения

Многие компоненты интерфейса управляют выбором значений. В одних случаях допустим только один выбранный элемент, в других — несколько одновременно. Библиотека Radix UI реализует оба подхода через единый концептуальный механизм управления состоянием.

Одиночные и множественные значения применяются в различных компонентах:

  • Accordion
  • ToggleGroup
  • Tabs
  • RadioGroup
  • Checkbox
  • Select

Основное различие между режимами заключается в структуре состояния:

Тип выбора Структура значения Поведение
Одиночное значение строка (string) выбран только один элемент
Множественные значения массив (string[]) выбран набор элементов

Radix UI не скрывает состояние внутри компонента, а предоставляет гибкую систему контролируемых и неконтролируемых состояний, что позволяет управлять значениями из внешнего состояния приложения.


Одиночное значение (Single Value)

Концепция

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

Внутри компонентов Radix это состояние обычно представлено строкой:

"value-1"

При выборе другого элемента предыдущее значение автоматически заменяется.


Пример: одиночный режим в Accordion

Компонент Accordion может работать в режиме, где одновременно открыт только один элемент.

import * as Accordion from "@radix-ui/react-accordion";

export default function Example() {
  return (
    <Accordion.Root type="single">
      <Accordion.Item value="item-1">
        <Accordion.Header>
          <Accordion.Trigger>Раздел 1</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>
          Содержимое первого раздела
        </Accordion.Content>
      </Accordion.Item>

      <Accordion.Item value="item-2">
        <Accordion.Header>
          <Accordion.Trigger>Раздел 2</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>
          Содержимое второго раздела
        </Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  );
}

Ключевой параметр:

type="single"

Этот режим обеспечивает следующие свойства:

  • одновременно открыт один элемент
  • открытие нового элемента закрывает предыдущий
  • состояние представлено одним значением

Управляемый режим (Controlled State)

Radix UI позволяет полностью контролировать выбранное значение через React-состояние.

const [value, setValue] = React.useState("item-1");

<Accordion.Root
  type="single"
  value={value}
  onValueCha nge={setValue}
>

Поведение:

  • value — текущее активное значение
  • onValueChange — обработчик изменения
  • состояние хранится в родительском компоненте

Это особенно важно в сложных интерфейсах, где выбор должен:

  • синхронизироваться с URL
  • сохраняться в глобальном состоянии
  • влиять на другие компоненты

Возможность закрытия активного элемента

В одиночном режиме по умолчанию всегда выбран один элемент. Однако поведение можно изменить.

Параметр:

collapsible

Пример:

<Accordion.Root type="single" collapsible>

Теперь возможно:

  • открыть элемент
  • повторно нажать на него
  • закрыть его полностью

В таком случае значение становится:

undefined

Множественные значения (Multiple Values)

Концепция

В режиме множественного выбора пользователь может активировать несколько элементов одновременно. Состояние компонента представлено массивом значений.

Пример состояния:

["item-1", "item-3", "item-5"]

Каждый элемент независимо добавляется или удаляется из массива.


Пример: множественный режим Accordion

<Accordion.Root type="multiple">
  <Accordion.Item value="item-1">
    <Accordion.Header>
      <Accordion.Trigger>Раздел 1</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Content>
      Контент
    </Accordion.Content>
  </Accordion.Item>

  <Accordion.Item value="item-2">
    <Accordion.Header>
      <Accordion.Trigger>Раздел 2</Accordion.Trigger>
    </Accordion.Header>
    <Accordion.Content>
      Контент
    </Accordion.Content>
  </Accordion.Item>
</Accordion.Root>

Особенности:

  • можно открыть несколько разделов
  • закрытие одного не влияет на другие
  • состояние — массив строк

Управление множественными значениями

Контролируемый режим выглядит следующим образом:

const [values, setValues] = React.useState(["item-1"]);

<Accordion.Root
  type="multiple"
  value={values}
  onValueCha nge={setValues}
/>

Тип состояния:

string[]

Пример изменения массива:

["item-1"] → ["item-1", "item-2"]
["item-1", "item-2"] → ["item-2"]

Radix автоматически управляет добавлением и удалением значений.


ToggleGroup: одиночный и множественный режим

Компонент ToggleGroup демонстрирует особенно наглядную разницу между режимами.


Одиночный выбор

import * as ToggleGroup from "@radix-ui/react-toggle-group";

<ToggleGroup.Root type="single">
  <ToggleGroup.Item value="bold">B</ToggleGroup.Item>
  <ToggleGroup.Item value="italic">I</ToggleGroup.Item>
  <ToggleGroup.Item value="underline">U</ToggleGroup.Item>
</ToggleGroup.Root>

Поведение:

  • активна только одна кнопка
  • нажатие на другую снимает предыдущую

Такой режим напоминает RadioGroup.


Множественный выбор

<ToggleGroup.Root type="multiple">
  <ToggleGroup.Item value="bold">B</ToggleGroup.Item>
  <ToggleGroup.Item value="italic">I</ToggleGroup.Item>
  <ToggleGroup.Item value="underline">U</ToggleGroup.Item>
</ToggleGroup.Root>

Поведение:

  • можно включить несколько опций
  • каждая кнопка независима

Этот режим напоминает набор чекбоксов.


Типы значений и их структура

Radix придерживается строгой типизации значений.

Одиночный режим

Тип значения:

string | undefined

Пример:

"tab-1"

или

undefined

если элемент закрыт.


Множественный режим

Тип значения:

string[]

Пример:

["bold", "italic"]

или

[]

если ничего не выбрано.


defaultValue и value

Radix использует два способа задания состояния.

defaultValue

Используется для неконтролируемых компонентов.

<Accordion.Root
  type="single"
  defaultValue="item-1"
/>

Или для множественного режима:

<Accordion.Root
  type="multiple"
  defaultValue={["item-1", "item-2"]}
/>

После инициализации состояние управляется внутри компонента.


value

Используется для контролируемых компонентов.

<Accordion.Root
  type="single"
  value={value}
  onValueCha nge={setValue}
/>

Или:

<Accordion.Root
  type="multiple"
  value={values}
  onValueCha nge={setValues}
/>

В этом случае Radix выступает только как UI-слой, а логика состояния находится в приложении.


Алгоритм изменения значений

Radix реализует стандартные операции над состоянием.

Для одиночного режима

Алгоритм:

1. пользователь выбирает элемент
2. значение становится равным value элемента
3. предыдущий элемент деактивируется

Если включен collapsible:

4. повторный клик очищает значение

Для множественного режима

Алгоритм:

1. пользователь нажимает элемент
2. если значение отсутствует — оно добавляется в массив
3. если значение уже есть — оно удаляется

Это можно представить как операцию:

toggle(value)

Типичные сценарии использования

Одиночные значения

Используются в ситуациях, где необходимо выбрать ровно один вариант.

Примеры интерфейсов:

  • переключение вкладок
  • выбор режима отображения
  • выбор одного фильтра
  • аккордеоны с единственным открытым разделом
  • группы радио-кнопок

Компоненты Radix:

  • Tabs
  • RadioGroup
  • Select
  • Accordion (single)
  • ToggleGroup (single)

Множественные значения

Используются в интерфейсах, где допускается комбинация опций.

Примеры:

  • фильтры
  • настройки интерфейса
  • форматирование текста
  • списки чекбоксов
  • множественные раскрывающиеся панели

Компоненты Radix:

  • Checkbox
  • ToggleGroup (multiple)
  • Accordion (multiple)

Управление состоянием в сложных интерфейсах

Множественные значения особенно важны в динамических интерфейсах.

Пример фильтрации:

["size-large", "color-red", "brand-nike"]

Каждый параметр можно включать и отключать независимо.

В React это часто реализуется через useState:

const [filters, setFilters] = useState([]);

Radix автоматически синхронизирует UI с этим состоянием.


Распространённые ошибки

Несоответствие типа значения

Ошибка:

type="multiple"
value="item-1"

Правильный вариант:

value={["item-1"]}

Использование defaultValue вместе с value

Некорректно:

<Accordion.Root
  value={value}
  defaultValue="item-1"
/>

Компонент должен быть либо:

  • контролируемым
  • неконтролируемым

Отсутствие onValueChange

Если используется value, необходимо передать обработчик:

onValueCha nge={setValue}

Иначе состояние будет заблокировано.


Архитектурное значение модели выбора

Подход Radix к одиночным и множественным значениям формирует унифицированную модель управления состоянием:

  1. каждый элемент имеет value
  2. контейнер хранит текущее состояние
  3. события передаются через onValueChange
  4. состояние может быть контролируемым или внутренним

Эта архитектура позволяет:

  • строить сложные интерфейсы
  • синхронизировать состояние компонентов
  • интегрировать UI с глобальными хранилищами
  • поддерживать предсказуемое поведение элементов управления.