---
# System prepended metadata

title: Прокидывать ref в кореневой элемент

---

# Прокидывать ref в кореневой элемент

В ходе обновления компонента «Checkbox» возникли концептуальные вопросы. Предлагаю вместе подумать над ответами, которые можно будет зафиксировать в принципах разработки UI kit.

…

**Вопрос первый. Прокидывать ref в кореневой элемент или по семантике?**

Представим, что в прикладном проекте используется компонент Checkbox

```javascript=
import * as React from 'react';
import { Checkbox } from 'uikit';

export const Example = React.memo(() => {
  const checkboxRef = React.useRef(null);

  const handleFormChange = () => {
    setTimeout(() => {
      if (checkboxRef.current && checkboxRef.current.checked) {
        checkboxRef.current.checked = false;
      }
    }, 5000);
  };

  const handleFormSubmit = (
    event
  ) => {
    event.preventDefault();

    alert(
      checkboxRef.current && checkboxRef.current.checked === true
        ? 'Получено согласие'
        : 'Получен отказ'
    );
  };

  return (
    <form onChange={handleFormChange} onSubmit={handleFormSubmit}>
      <div>
        <Checkbox
          name="agreement"
          ref={checkboxRef}  // строка 32
        >
          Согласен с условиями на 5 секунд
        </Checkbox>
      </div>

      <div>
        <button type="submit">Отправить</button>
      </div>
    </form>
  );
});

Example.displayName = nameof(Example);
```

Итого получится такой компонент Example:
https://i.imgur.com/AViRAIJ.mp4

…

Вопрос: в строке 32 `<Checkbox name="agreement" ref={checkboxRef}>` на что должен указывать ref?

**Вариант 🅰️** — по семантике. Сослаться на `<input type="checkbox" />`, который содержится внутри компонента `Checkbox`. Аргумент за: «пропсы идут в input однозначно, почему ref должен идти в другой элемент?».

**Вариант 🅱️** — в кореневой элемент. Сослаться на `<label>`, потому что он является корневым элементом компонента `Checkbox`. Аргумент за: «так уже сделано в других компонентах uikit». Контраргумент: «мы можем выбрать другой подход для будущих компонентов, а существующие со временем обновить, нужно эволюционировать — иметь механизм принятия изменений».

```javascript
/**
 * Реализация компонента Checkbox в uikit
 */
export const Checkbox = React.forwardRef(({ children, ...props }, ref) => (
  <Label
    {...props.label}
    ref={ref} // ref тут? Вариант 🅱️
  >
    <Input
      {...props}
      type="checkbox"
      ref={ref} // ref тут? Вариант 🅰️
      data-indeterminate={props.indeterminate === true || void 0}
    />

    <Icon {...props.icon} />

    {children && (
      <ChildrenWrapper {...props.childrenWrapper}>{children}</ChildrenWrapper>
    )}
  </Label>
));

```

…

Дополнение про вариант 🅰️: как взаимодействовать с ref корневого элемента у комопонента Checkbox? 

```javascript
/**
 * Для ответа на вопрос: расширем логику handleFormChange,
 * теперь она будет подсвечивать на 1 секунду весь 
 * внутренний лейбл у checkbox при изменении.
 * 
 * Блоки нового кода помечены 💥.
 */

import * as React from 'react';
import { Checkbox } from 'uikit';

export const Example = React.memo(() => {
  const labelRef = React.useRef(null); // 💥
  const checkboxRef = React.useRef(null);

  const handleFormChange = () => {
    setTimeout(() => {
      if (checkboxRef.current && checkboxRef.current.checked) {
        checkboxRef.current.checked = false;

        if (labelRef.current) {  // 💥
          labelRef.current.style.backgroundColor = 'lightpink';

          setTimeout(() => {
            labelRef.current.style.backgroundColor = '';
          }, 1000);
        }
      }
    }, 5000);
  };

  const handleFormSubmit = (event) => {
    event.preventDefault();

    alert(
      checkboxRef.current && checkboxRef.current.checked === true
        ? 'Получено согласие'
        : 'Получен отказ'
    );
  };

  return (
    <form onChange={handleFormChange} onSubmit={handleFormSubmit}>
      <div>
        <Checkbox
          name="agreement"
          ref={checkboxRef}
          label={{ ref: labelRef }} // 💥
        >
          Согласен с условиями на 5 секунд
        </Checkbox>
      </div>

      <div>
        <button type="submit">Отправить</button>
      </div>
    </form>
  );
});

Example.displayName = nameof(Example);
```

…

**Вопрос второй. Нужен доступ к пропсам внутренних компонентов?**

В компоненте Checkbox для передачи свойств внутренним компонентам: Label, Icon, ChildrenWrapper, заведены специальные одноименные свойства: label, icon, childrenWrapper. В них же можно передать ref, как это было продемонстрировано в примере выше.

**Вариант 👍🏽** — так делать можно

**Вариант 👎🏽** — так делать не надо
