Props и emits, однонаправленный поток данных
↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая
Зачем это на собесе
Базовый принцип: данные вниз (props), события вверх (emits). Нарушение приводит к трудноотлаживаемому коду.
Объяснение
<!-- Child.vue -->
<script setup lang="ts">
interface Props { order: Order; readonly?: boolean; size?: "sm" | "md" }
const props = withDefaults(defineProps<Props>(), { readonly: false, size: "md" });
const emit = defineEmits<{ save: [order: Order]; cancel: []; "update:qty": [value: number] }>();
</script>
<template>
<button :disabled="readonly" @click="emit('save', order)">Сохранить</button>
</template>
<!-- Parent.vue -->
<OrderCard :order="o" size="sm" @save="onSave" @cancel="close" />Правила:
- Props передают данные родитель → потомок; потомок не мутирует их (предупреждение). Нужна локальная копия —
ref(props.x)илиcomputedсget/set. - Emits — события потомок → родитель; объявляйте (
defineEmits) для документации, типизации и корректного поведения нативных событий. - Булевы props: наличие атрибута =
true(<Btn disabled />). - Объекты и массивы передаются по ссылке; мутация вложенных полей props технически возможна, но нарушает поток данных.
- Валидация (runtime):
type,required,default,validator; в TS — интерфейс.
// Runtime-объявление
defineProps({ qty: { type: Number, required: true, validator: (v: number) => v > 0 } });
// Копия для редактирования
const draft = ref({ ...props.order });
watch(() => props.order, (o) => (draft.value = { ...o }));Регистр: defineProps({ userName }) → :user-name в шаблоне (kebab-case).
Когда props «слишком много» (prop drilling): provide/inject, стор (Pinia) или слоты.
Нюансы и подводные камни
- Значения по умолчанию для объектов/массивов — функциями-фабриками.
- Реактивная деструктуризация props появилась в 3.5; до этого —
toRefs. - Не передавайте функции-коллбэки вместо событий без причины: события — идиоматичный контракт.
- Событие
update:modelValue— основаv-model(см. v-model на компонентах и defineModel). - Пропсы, не объявленные, попадают в
$attrs(см. Атрибуты: $attrs и inheritAttrs).
Практика
- Сделайте карточку с типизированными props и событием
save. - Реализуйте редактирование с локальной копией без мутации props.
- Устраните prop drilling через
provide/inject.
Вопросы с ответами
Почему нельзя мутировать props?
Данные принадлежат родителю; мутация нарушает однонаправленный поток и делает изменения непредсказуемыми.
Как передать данные вверх?
Через события (
emit),v-modelили общий стор.