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