Пропсы: defineProps и валидация

Учимся передавать данные в компонент сверху вниз через пропсы: объявляем их через defineProps, задаём типы, обязательность и значения по умолчанию.

Проп (prop) — именованный параметр, который родительский компонент передаёт дочернему, чтобы настроить его поведение или содержимое.

Зачем нужны пропсы

Компонент UserCard бесполезен, если всегда показывает одно и то же. Пропсы делают его настраиваемым: один и тот же компонент рисует разных пользователей в зависимости от переданных данных.

Объявление через defineProps

В <script setup> пропсы объявляют макросом defineProps. В шаблоне они доступны напрямую по имени:

<!-- UserCard.vue -->
<template>
  <div class="card">
    <h3>{{ name }}</h3>
    <p>Возраст: {{ age }}</p>
  </div>
</template>

<script setup>
const props = defineProps(['name', 'age'])
</script>

Родитель передаёт пропсы как атрибуты. Статичную строку — обычным атрибутом, динамическое значение — через : (это привязка из раздела 2):

<!-- App.vue -->
<template>
  <UserCard name="Аня" :age="25" />
  <UserCard :name="user.name" :age="user.age" />
</template>

<script setup>
import { ref } from 'vue'
import UserCard from './components/UserCard.vue'
const user = ref({ name: 'Борис', age: 30 })
</script>

Обратите внимание: :age="25" с двоеточием передаёт число 25, а age="25" без двоеточия передало бы строку "25".

Типы, обязательность, значения по умолчанию

Объектная форма defineProps добавляет проверку типов и значения по умолчанию. Vue предупредит в консоли, если передан не тот тип:

<script setup>
const props = defineProps({
  name: { type: String, required: true },
  age: { type: Number, default: 0 },
  isAdmin: { type: Boolean, default: false },
})
</script>

Поток данных только вниз

Пропсы однонаправленны: данные текут от родителя к ребёнку, но не обратно. Дочерний компонент не должен менять свой проп — это лишь сломает предсказуемость. Если ребёнку нужно сообщить об изменении наверх — он испускает событие (следующий урок). Смоделируем однонаправленный поток:

// Родитель владеет данными
const parentState = { count: 10 };

// Ребёнок получает КОПИЮ значения как проп
function child(propCount) {
  // менять локально можно, но на родителя это не влияет
  let local = propCount;
  local = local + 1;
  return local;
}

const result = child(parentState.count);
console.log("Внутри ребёнка:", result);
console.log("У родителя осталось:", parentState.count);

Вывод:

Внутри ребёнка: 11
У родителя осталось: 10

Итог

  • Пропсы передают данные от родителя к ребёнку и объявляются через defineProps.
  • Объектная форма задаёт type, required и default с проверкой в консоли.
  • :age="25" передаёт число, age="25" — строку.
  • Поток однонаправленный: ребёнок не меняет проп, а сообщает наверх событием.
Проверьте себя
1. Каким макросом объявляют пропсы в <script setup>?
AuseProps()
BdefineProps()
Cprops()
DcreateProps()
2. В чём разница между age="25" и :age="25" при передаче пропа?
AРазницы нет
Bage="25" передаёт строку "25", а :age="25" (с двоеточием) передаёт число 25 как выражение
C:age="25" вызовет ошибку
Dage="25" передаёт число, а :age="25" — строку
3. Можно ли дочернему компоненту менять полученный проп?
AДа, это обычная практика
BНет: поток данных однонаправленный, ребёнок не меняет проп, а сообщает об изменении событием наверх
CДа, но только если проп — объект
DДа, через двойное двоеточие
Поддержать проект