Props и emits, однонаправленный поток данных

↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Базовый принцип: данные вниз (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).

Практика

  1. Сделайте карточку с типизированными props и событием save.
  2. Реализуйте редактирование с локальной копией без мутации props.
  3. Устраните prop drilling через provide/inject.

Вопросы с ответами

Связанные темы