Связывание с контролами

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


Контролируемые и неконтролируемые компоненты

Контролируемый компонент — это компонент, состояние которого полностью управляется извне через пропсы. Такой компонент получает текущие значения состояния через пропсы и уведомляет об изменениях через callback-функции.

Пример с компонентом Toggle:

import * as Toggle from '@radix-ui/react-toggle';
import { useState } from 'react';

function ControlledToggle() {
  const [pressed, setPressed] = useState(false);

  return (
    <Toggle.Root pressed={pressed} onPressedCha nge={setPressed}>
      {pressed ? 'Включено' : 'Выключено'}
    </Toggle.Root>
  );
}

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

Пример неконтролируемого Toggle:

<Toggle.Root defaultPressed={true} onPressedCha nge={(state) => console.log(state)}>
  Включить/Выключить
</Toggle.Root>
  • pressed и defaultPressed — ключевые пропсы для управления состоянием.
  • onPressedChange — callback для получения изменений.

Связывание нескольких контролов

Radix UI поддерживает работу с группами контролов, что особенно важно для компонентов вроде RadioGroup или CheckboxGroup.

Пример с RadioGroup:

import * as RadioGroup from '@radix-ui/react-radio-group';
import { useState } from 'react';

function ControlledRadioGroup() {
  const [value, setValue] = useState('option1');

  return (
    <RadioGroup.Root value={value} onValueCha nge={setValue}>
      <RadioGroup.Item value="option1">Опция 1</RadioGroup.Item>
      <RadioGroup.Item value="option2">Опция 2</RadioGroup.Item>
      <RadioGroup.Item value="option3">Опция 3</RadioGroup.Item>
    </RadioGroup.Root>
  );
}

Ключевые моменты:

  • value — текущее выбранное значение.
  • onValueChange — обработчик изменения выбранного значения.
  • Все элементы RadioGroup.Item синхронизируются с RadioGroup.Root автоматически.

Связывание с формами

Radix UI можно легко интегрировать с формами, используя контролируемые компоненты.

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

import * as Checkbox from '@radix-ui/react-checkbox';
import { useState } from 'react';

function FormWithCheckbox() {
  const [checked, setChecked] = useState(false);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Checkbox value:', checked);
  };

  return (
    <form onSub mit={handleSubmit}>
      <Checkbox.Root checked={checked} onCheckedCha nge={setChecked}>
        Согласен с условиями
      </Checkbox.Root>
      <button type="submit">Отправить</button>
    </form>
  );
}
  • Связывание состояния checked с пропсами позволяет использовать его в обработчике формы.
  • Callback onCheckedChange автоматически передаёт новое состояние при клике.

Интеграция с внешними состояниями

Radix UI отлично работает с глобальными состояниями и менеджерами вроде Redux, Zustand или Recoil.

Пример с Zustand:

import * as Toggle from '@radix-ui/react-toggle';
import { create } from 'zustand';

const useStore = create((set) => ({
  pressed: false,
  toggle: () => set((state) => ({ pressed: !state.pressed })),
}));

function GlobalToggle() {
  const { pressed, toggle } = useStore();

  return <Toggle.Root pressed={pressed} onPressedCha nge={toggle}>Тоггл</Toggle.Root>;
}
  • Состояние хранится централизованно.
  • Любые изменения через Radix-компонент мгновенно отражаются в глобальном состоянии.

Полезные пропсы для связывания

Пропс Описание
defaultValue Начальное значение для неконтролируемого компонента.
value Текущее состояние для контролируемого компонента.
onValueChange Callback при изменении значения (Radio, Sel ect).
defaultChecked Начальное состояние для чекбоксов и переключателей.
checked Контролируемое состояние для чекбоксов и переключателей.
onCheckedChange Callback при изменении состояния чекбокса/переключателя.

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


Декомпозиция компонентов для гибкой интеграции

Radix UI использует паттерн compound components, что облегчает связывание с контролами:

  • Root отвечает за логику состояния.
  • Item или Trigger управляют визуальной частью и передают события обратно в Root.
  • Возможность полностью управлять состоянием через пропсы без изменения внутренней реализации.

Пример с Accordion:

import * as Accordion fr om '@radix-ui/react-accordion';
import { useState } from 'react';

function ControlledAccordion() {
  const [value, setValue] = useState('item-1');

  return (
    <Accordion.Root type="single" value={value} onValueCha nge={setValue}>
      <Accordion.Item value="item-1">
        <Accordion.Header>
          <Accordion.Trigger>Раздел 1</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>Контент раздела 1</Accordion.Content>
      </Accordion.Item>
      <Accordion.Item value="item-2">
        <Accordion.Header>
          <Accordion.Trigger>Раздел 2</Accordion.Trigger>
        </Accordion.Header>
        <Accordion.Content>Контент раздела 2</Accordion.Content>
      </Accordion.Item>
    </Accordion.Root>
  );
}
  • Состояние value контролирует, какой элемент открыт.
  • onValueChange позволяет синхронизировать открытие элементов с внешней логикой.

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