# Прокидывать 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, как это было продемонстрировано в примере выше.
**Вариант 👍🏽** — так делать можно
**Вариант 👎🏽** — так делать не надо