Для чего нужен defineExpose во Vue 3
Что проверяют
Знаете ли вы, что компонент на <script setup> по умолчанию закрыт, и понимаете ли, когда родителю действительно нужно вызывать методы ребёнка. Следом обычно спрашивают, чем это хуже props и событий и как такой доступ типизировать.
Как отвечать
Компонент с <script setup> ничего из своего setup не отдаёт наружу: родитель, получив экземпляр через template ref, не увидит ни переменных, ни функций. defineExpose явно открывает нужную часть.
- это макрос компилятора: как
definePropsиdefineEmits, его не импортируют изvue, он доступен внутри<script setup>сам. Вызывается на верхнем уровне, не внутри функции; - что отдавать: методы императивного управления, которые плохо ложатся на props:
focus()у поля,open()у модалки,validate()иreset()у формы,scrollToTop()у списка; - как получить: в родителе
const form = useTemplateRef('form')(с Vue 3.5) или обычныйref(null)с тем же именем, что в атрибутеref. Открытые черезdefineExposeref при доступе через экземпляр разворачиваются,.valueписать не нужно; - типизация:
useTemplateRef<InstanceType<typeof MyForm>>('form'), тогда вызовform.value?.validate()проверяется компилятором; - аналоги: в Options API опция
expose: ['validate'], в обычной функцииsetup()контекст вторым аргументом даётexpose().
Хороший итог: данные сверху вниз идут через props, события снизу вверх через emit, двусторонняя связь через v-model, а defineExpose оставляют для редких императивных действий.
Где спотыкаются
Импортируют defineExpose из vue. Работать будет, но компилятор выдаст предупреждение, и интервьюер поймёт, что природа макросов вам не ясна.
Обращаются к экземпляру ребёнка слишком рано, прямо на верхнем уровне <script setup> родителя. До монтирования ref равен null, методы вызывают в onMounted() или по действию пользователя.
Превращают defineExpose в канал для состояния: родитель читает и меняет внутренние данные ребёнка напрямую. Поток данных становится непрозрачным, а компонент перестаёт быть заменяемым.