логотип PurpleSchool
логотип PurpleSchool

Передача и использование props в Vue 3 для взаимодействия компонентов

Автор

Олег Марков

Введение

В приложениях на Vue 3 компоненты часто “разговаривают” между собой, обмениваясь данными для построения динамичных пользовательских интерфейсов. Одним из главных инструментов такого взаимодействия выступают props — специальные свойства, позволяющие родительскому компоненту передавать данные своим потомкам. Правильное использование props делает архитектуру приложения более модульной, предсказуемой и удобной для поддержки.

Смотрите, я покажу вам, как работает эта система: родительский компонент отправляет значения в дочерний, а тот — использует их для отображения или логики. Мы рассмотрим, как объявлять props, задавать им типы, передавать значения различного типа, применять валидацию и отслеживать изменения. Давайте вместе посмотрим на примерах, как всё это реализовано на практике.

Как работают props в Vue 3

Основная концепция передачи данных

Props (от “properties”) — это способ передать значения из родительского компонента в дочерний. Ключевой идеей props является однонаправленный поток данных (“top-down”), то есть данные идут только от родителя к наследнику, а не наоборот. Тем самым props помогают избегать непредсказуемого изменения данных и делают поведение приложения прозрачным.

Пример передачи props

Допустим, у вас есть два компонента: ParentComponent и ChildComponent. Родитель передаёт сообщение в дочерний компонент:

<!-- ParentComponent.vue -->
<template>
  <ChildComponent message="Привет, Vue 3!" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
</script>
<!-- ChildComponent.vue -->
<template>
  <p>{{ message }}</p>
</template>
<script setup>
// Здесь мы явно объявляем пропс 'message'
defineProps(['message'])
</script>

Как видите, родитель передаёт значение через атрибут, а дочерний его принимает и отображает.

Объявление, типизация и валидация props

В Vue 3, особенно при использовании <script setup>, объявление props осуществляется с помощью функции defineProps.

Объявление props как массива строк

// Принимаем только перечисленные пропсы (в данном случае, message)
const props = defineProps(['message'])

Часто достаточно просто объявить список props, которые вы собираетесь использовать.

Типизация и объектная форма объявления

Более гибко — использовать объект. Давайте посмотрим, как добавить тип и значения по умолчанию:

const props = defineProps({
  message: String,
  count: {
    type: Number,
    required: true, // Обязательный пропс
    default: 0 // Значение по умолчанию
  }
})

Здесь message обязательно должен быть строкой, а count — числом с дефолтным значением 0. Если родитель не передаст count, компонент сам подставит это значение.

Валидация props

Можно проверять значения и с помощью validator:

const props = defineProps({
  status: {
    type: String,
    validator: (value) => ['success', 'error', 'pending'].includes(value)
  }
})
// Теперь статус может быть только одним из трёх указанных вариантов

Если переданное значение не проходит проверку — консоль покажет предупреждение, что полезно при отладке.

Использование props в шаблоне и скрипте

Любое значение, объявленное как prop, становится реактивным и доступно в шаблоне, скрипте и вычисляемых свойствах. Например:

<template>
  <h2>Счетчик: {{ count }}</h2>
</template>
<script setup>
const props = defineProps({
  count: Number
})
// Вы также можете использовать props.count внутри функций
</script>

Передача данных различных типов

Props могут быть любыми: числа, строки, объекты, массивы, функции.

Передача объектов и массивов

<!-- ParentComponent.vue -->
<ChildComponent :user="{ name: 'Елена', age: 32 }" :tasks="['Покупки', 'Учёба']" />
// ChildComponent.vue
const props = defineProps({
  user: Object,
  tasks: Array
})
// Теперь props.user — это объект, а props.tasks — массив

Передача функций как props

Давайте посмотрим на передачу обработчика событий:

<!-- ParentComponent.vue -->
<ChildComponent :onSubmit="handleSubmit" />
// ChildComponent.vue
const props = defineProps({
  onSubmit: Function
})
// Где-то внутри компонента можно вызвать: props.onSubmit()

Это удобно, например, для коллбэков, когда нужно, чтобы дочерний компонент “сообщил” о каком-то действии родителю.

Reactivity: что можно и нельзя делать с prop

Props в дочернем компоненте реактивны — если родитель обновляет значение, дочерний компонент увидит новое значение.

Однако Vue запрещает напрямую изменять переданный prop внутри дочернего компонента — это вызовет предупреждение. Смотрите, как это проявляется:

// Такое делать нельзя!
props.count++ // Вы получите ошибку в консоли

Чтобы обойти это (например, если вы хотите временно изменить значение), создайте локальное состояние:

import {ref, watch} from 'vue'

const props = defineProps({ count: Number })
const localCount = ref(props.count)

watch(() => props.count, (newVal) => {
  localCount.value = newVal
})
// Теперь изменяйте localCount, а обновления от родителя попадут сюда через watch

Значения по умолчанию при отсутствии пропса

Если пропс не передан родителем, можно определить значение по умолчанию:

const props = defineProps({
  username: {
    type: String,
    default: 'Гость'
  }
})

Теперь, если username не указан при использовании компонента, он будет 'Гость'.

Обязательные (required) props

Добавьте required: true, чтобы получать предупреждение, если родитель не передал важный prop:

const props = defineProps({
  id: {
    type: [Number, String],
    required: true
  }
})

Передача всех props через v-bind

Если у вас есть объект со множеством свойств, удобно передавать его целиком так:

<ChildComponent v-bind="userProps" />
<!-- Все поля userProps попадут в дочерний компонент как отдельные пропсы -->

В скрипте родителя:

const userProps = {
  name: 'Олег',
  age: 40,
  status: 'active'
}

Дочерний компонент определяет ожидаемые props:

const props = defineProps({
  name: String,
  age: Number,
  status: String
})

Примеры типичных паттернов передачи props

Алиас пропсов в дочерних компонентах

Иногда хочется переименовать пропс, чтобы избежать конфликтов. Используйте композитные свойства:

const props = defineProps({ message: String })
const localMessage = computed(() => props.message)

“Дочерний компонент как шаблонное API” (Scoped Slots)

В Vue 3 slots и props тесно связаны. Родитель может выступать поставщиком UI, а дочерний компонент — передавать данные через scoped slots:

<ChildComponent v-slot="{ status }">
  <span>Статус: {{ status }}</span>
</ChildComponent>

Внутри дочернего компонента определяйте данные для вывода через slot:

<template #default="{ status }">
  <slot :status="currentStatus"></slot>
</template>

Мутация объектов и массивов, переданных через props

Если вы передаете объект или массив как prop, сам указатель на объект менять нельзя, но внутренние поля — можно (хотя это не рекомендуется). Это потому, что переданный объект — это ссылка на оригинал.

// Такое изменение внутреннего свойства будет работать:
props.user.name = 'Другое Имя'
// Но это не лучшая практика, старайтесь избегать мутаций prop

Более надёжный вариант — клонировать объект в локальное состояние.

Жизненный цикл props: отслеживание изменений

Вы можете отслеживать изменение любого пропса с помощью watch:

import {watch} from 'vue'

const props = defineProps({ value: Number })

watch(() => props.value, (newVal, oldVal) => {
  // Здесь срабатывает реакция на изменение prop
})

Это полезно, когда на изменение пропса нужно отреагировать выполнением действия.

Reactivity мегаподробнее

  • Числовые, строковые, булевые пропсы — обновляются мгновенно при изменении родителем.
  • Объекты и массивы — реактивны по ссылке (если внутри поля объекта меняются, дочерний это увидит).
  • Простое “переприсваивание” пропса в дочернем не приведет к обновлению родителя.

Передача props во вложенные компоненты

Если у вас есть многоуровневая иерархия компонентов, передавать prop “вниз” приходится вручную:

<!-- App.vue -->
<ParentComponent user="..."/>
<!-- ParentComponent.vue -->
<ChildComponent :user="user"/>
<!-- ChildComponent.vue -->
// Вот здесь проп user доходит до самой глубины
const props = defineProps({ user: Object })

Для сложных случаев советую обратить внимание на Provide/Inject или глобальные state management решения.

Ограничения: что не стоит делать с props

  • Не изменяйте prop напрямую внутри дочернего компонента.
  • Не используйте props для передачи данных “вверх” (от дочернего к родителю) — для этого применяют события (emit).
  • Не полагайтесь на мутацию объектов через prop — это может привести к багам.

Лучшие практики

  • Явно объявляйте все используемые props.
  • Типизируйте props для лучшей читаемости и отладки.
  • Используйте значения по умолчанию и валидацию.
  • По возможности делайте prop неизменяемым внутри дочернего компонента.
  • Minimize props (передавайте только нужные данные).

Заключение

Props — это фундаментальная механика, на которой строится взаимодействие компонентов в Vue 3. Они обеспечивают односторонний поток данных от родителя к потомку, дают большие возможности по типизации и валидации и делают логику передачи данных прозрачной и управляемой. Изучив основы работы с props, вы сможете строить масштабируемые, модульные и надёжные Vue-приложения.

Частозадаваемые технические вопросы по теме статьи и ответы на них

Как заставить дочерний компонент отправить измененное значение пропса обратно родителю?

Вам нужно использовать механизм событий (emit) вместо прямого изменения пропса. Например:

const emit = defineEmits(['update'])
function updateValue(newValue) {
  emit('update', newValue)
}

Родитель слушает событие:
<ChildComponent @update="handleUpdate" />


Как динамически изменить список props, принимаемых компонентом?

Вариативно “переключать” props на лету нельзя. Компонент принимает только те props, которые объявлены (или все неограниченно, если не указан defineProps). Чтобы пропс был реактивным, просто обновляйте значение у родителя — оно мгновенно попадет в дочерний компонент.


Как сделать prop обязательным только при определённых условиях?

Добавьте computed валидацию в родителе и условно передавайте prop только при удовлетворении условий. Локальная валидация через validator не поддерживает динамическое required.


Можно ли передавать JSX/шаблоны как prop?

Для этого используют scoped slots или функцию render-prop, обычный prop не рассчитан на передачу готового шаблона.


Как запретить передачу “лишних” props?

Vue по умолчанию пропустит лишние props, не объявленные в defineProps, только если компонент объявлен с <script setup>. Для обычных компонентов используйте inheritAttrs: false и явно устанавливайте только необходимые props в шаблон.

Стрелочка влевоПонимание и использование provide inject для передачи данных между компонентамиПередача данных между компонентами с помощью props в Vue jsСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний