Props
Esta página asume que ya has leído Fundamentos de Componentes. Léelo primero si eres nuevo en los componentes.
Declaración de Props
Los componentes de Vue requieren una declaración explícita de props para que Vue sepa qué props externas pasadas al componente deben tratarse como atributos de paso directo (lo cual se discutirá en su sección dedicada).
En SFCs que usan <script setup>, las props pueden declararse usando la macro defineProps():
vue
<script setup>
const props = defineProps(['foo'])
console.log(props.foo)
</script>En componentes que no usan <script setup>, las props se declaran usando la opción props:
js
export default {
props: ['foo'],
setup(props) {
// setup() recibe props como primer argumento.
console.log(props.foo)
}
}Nótese que el argumento pasado a defineProps() es el mismo que el valor proporcionado a la opción props: la misma API de opciones de props se comparte entre los dos estilos de declaración.
Además de declarar las props usando un array de strings, también podemos usar la sintaxis de objeto:
js
// en <script setup>
defineProps({
title: String,
likes: Number
})js
// en no-<script setup>
export default {
props: {
title: String,
likes: Number
}
}Para cada propiedad en la sintaxis de declaración de objeto, la clave es el nombre de la prop, mientras que el valor debe ser la función constructora del tipo esperado.
Esto no solo documenta tu componente, sino que también advertirá a otros desarrolladores que usen tu componente en la consola del navegador si pasan el tipo incorrecto. Discutiremos más detalles sobre la validación de props más adelante en esta página.
Si estás usando TypeScript con <script setup>, también es posible declarar props usando anotaciones de tipo puras:
vue
<script setup lang="ts">
defineProps<{
title?: string
likes?: number
}>()
</script>Más detalles: Tipado de Props de Componentes
Desestructuración Reactiva de Props
El sistema de reactividad de Vue rastrea el uso del estado basándose en el acceso a las propiedades. Por ejemplo, cuando accedes a props.foo en un getter computado o un watcher, la prop foo se rastrea como una dependencia.
Así, dado el siguiente código:
js
const { foo } = defineProps(['foo'])
watchEffect(() => {
// se ejecuta solo una vez antes de la 3.5
// se vuelve a ejecutar cuando la prop "foo" cambia en la 3.5+
console.log(foo)
})En la versión 3.4 y anteriores, foo es una constante real y nunca cambiará. En la versión 3.5 y posteriores, el compilador de Vue antepone automáticamente props. cuando el código en el mismo bloque <script setup> accede a variables desestructuradas de defineProps. Por lo tanto, el código anterior se vuelve equivalente al siguiente:
js
const props = defineProps(['foo'])
watchEffect(() => {
// `foo` transformado a `props.foo` por el compilador
console.log(props.foo)
})Además, puedes usar la sintaxis de valores predeterminados nativa de JavaScript para declarar valores predeterminados para las props. Esto es particularmente útil cuando se utiliza la declaración de props basada en tipos:
ts
const { foo = 'hola' } = defineProps<{ foo?: string }>()Si prefieres tener una distinción visual mayor entre las props desestructuradas y las variables normales en tu IDE, la extensión de VSCode de Vue proporciona una configuración para habilitar inlay-hints para las props desestructuradas.
Pasando Props Desestructuradas a Funciones
Cuando pasamos una prop desestructurada a una función, por ejemplo:
js
const { foo } = defineProps(['foo'])
watch(foo /* ... */)Esto no funcionará como se espera porque es equivalente a watch(props.foo, ...) - estamos pasando un valor en lugar de una fuente de datos reactiva a watch. De hecho, el compilador de Vue detectará tales casos y lanzará una advertencia.
De forma similar a cómo podemos observar una prop normal con watch(() => props.foo, ...), podemos observar una prop desestructurada también envolviéndola en un getter:
js
watch(() => foo /* ... */)Además, este es el enfoque recomendado cuando necesitamos pasar una prop desestructurada a una función externa mientras se mantiene la reactividad:
js
useComposable(() => foo)La función externa puede llamar al getter (o normalizarlo con toValue) cuando necesite rastrear los cambios de la prop proporcionada, por ejemplo, en una computada o un watcher getter.
Detalles de Pase de Props
Casos de Nombres de Props
Declaramos nombres de props largos usando camelCase porque esto evita tener que usar comillas al usarlos como claves de propiedad, y nos permite referenciarlos directamente en expresiones de template porque son identificadores JavaScript válidos:
js
defineProps({
greetingMessage: String
})template
<span>{{ greetingMessage }}</span>Técnicamente, también puedes usar camelCase al pasar props a un componente hijo (excepto en templates en el DOM). Sin embargo, la convención es usar kebab-case en todos los casos para alinearse con los atributos HTML:
template
<MyComponent greeting-message="hola" />Usamos PascalCase para etiquetas de componentes cuando es posible porque mejora la legibilidad de el template al diferenciar los componentes de Vue de los elementos nativos. Sin embargo, no hay tanto beneficio práctico en usar camelCase al pasar props, por lo que elegimos seguir las convenciones de cada lenguaje.
Props Estáticas vs. Dinámicas
Hasta ahora, has visto props pasadas como valores estáticos, como en:
template
<BlogPost title="Mi viaje con Vue" />También has visto props asignadas dinámicamente con v-bind o su atajo :, como en:
template
<!-- Asigna dinámicamente el valor de una variable -->
<BlogPost :title="post.title" />
<!-- Asigna dinámicamente el valor de una expresión compleja -->
<BlogPost :title="post.title + ' de ' + post.author.name" />Pasando Diferentes Tipos de Valores
En los dos ejemplos anteriores, pasamos valores de string, pero cualquier tipo de valor puede pasarse a una prop.
Número
template
<!-- Aunque `42` es estático, necesitamos v-bind para decirle a Vue que -->
<!-- esto es una expresión JavaScript en lugar de un string. -->
<BlogPost :likes="42" />
<!-- Asigna dinámicamente el valor de una variable. -->
<BlogPost :likes="post.likes" />Booleano
template
<!-- Incluir la prop sin valor implicará `true`. -->
<BlogPost is-published />
<!-- Aunque `false` es estático, necesitamos v-bind para decirle a Vue que -->
<!-- esto es una expresión JavaScript en lugar de un string. -->
<BlogPost :is-published="false" />
<!-- Asigna dinámicamente el valor de una variable. -->
<BlogPost :is-published="post.isPublished" />Array
template
<!-- Aunque el array es estático, necesitamos v-bind para decirle a Vue que -->
<!-- esto es una expresión JavaScript en lugar de un string. -->
<BlogPost :comment-ids="[234, 266, 273]" />
<!-- Asigna dinámicamente el valor de una variable. -->
<BlogPost :comment-ids="post.commentIds" />Objeto
template
<!-- Aunque el objeto es estático, necesitamos v-bind para decirle a Vue que -->
<!-- esto es una expresión JavaScript en lugar de un string. -->
<BlogPost
:author="{
name: 'Verónica',
company: 'Veridian Dynamics'
}"
/>
<!-- Asigna dinámicamente el valor de una variable. -->
<BlogPost :author="post.author" />Enlazando Múltiples Propiedades Usando un Objeto
Si deseas pasar todas las propiedades de un objeto como props, puedes usar v-bind sin un argumento (v-bind en lugar de :prop-name). Por ejemplo, dado un objeto post:
js
const post = {
id: 1,
title: 'Mi Viaje con Vue'
}El siguiente template:
template
<BlogPost v-bind="post" />Será equivalente a:
template
<BlogPost :id="post.id" :title="post.title" />Flujo de Datos Unidireccional
Todas las props forman un enlace unidireccional descendente entre la propiedad hija y la propiedad padre: cuando la propiedad padre se actualiza, fluirá hacia el hijo, pero no al revés. Esto evita que los componentes hijos muten accidentalmente el estado del padre, lo que puede dificultar la comprensión del flujo de datos de tu aplicación.
Además, cada vez que el componente padre se actualiza, todas las props en el componente hijo se actualizarán con el valor más reciente. Esto significa que no debes intentar mutar una prop dentro de un componente hijo. Si lo haces, Vue te advertirá en la consola:
js
const props = defineProps(['foo'])
// ❌ advertencia, ¡las props son de solo lectura!
props.foo = 'bar'Normalmente, hay dos casos en los que es tentador mutar una prop:
La prop se utiliza para pasar un valor inicial; el componente hijo quiere usarlo como una propiedad de datos local después. En este caso, lo mejor es definir una propiedad de datos local que use la prop como su valor inicial:
jsconst props = defineProps(['initialCounter']) // counter solo usa props.initialCounter como valor inicial; // está desconectado de futuras actualizaciones de props. const counter = ref(props.initialCounter)La prop se pasa como un valor bruto que necesita ser transformado. En este caso, lo mejor es definir una propiedad computada usando el valor de la prop:
jsconst props = defineProps(['size']) // propiedad computada que se autoactualiza cuando la prop cambia const normalizedSize = computed(() => props.size.trim().toLowerCase())
Mutando Props de Objetos / Arrays
Cuando se pasan objetos y arrays como props, aunque el componente hijo no puede mutar el enlace de la prop, sí podrá mutar las propiedades anidadas del objeto o array. Esto se debe a que en JavaScript los objetos y arrays se pasan por referencia, y es excesivamente costoso para Vue evitar tales mutaciones.
El principal inconveniente de tales mutaciones es que permiten al componente hijo afectar el estado del padre de una manera que no es obvia para el componente padre, lo que potencialmente dificulta el razonamiento sobre el flujo de datos en el futuro. Como mejor práctica, debes evitar tales mutaciones a menos que el padre y el hijo estén fuertemente acoplados por diseño. En la mayoría de los casos, el hijo debe emitir un evento para permitir que el padre realice la mutación.
Validación de Props
Los componentes pueden especificar requisitos para sus props, como los tipos que ya has visto. Si no se cumple un requisito, Vue te advertirá en la consola de JavaScript del navegador. Esto es especialmente útil al desarrollar un componente que está destinado a ser utilizado por otros.
Para especificar validaciones de prop, puedes proporcionar un objeto con requisitos de validación a la macro defineProps(), en lugar de un array de strings. Por ejemplo:
js
defineProps({
// Verificación de tipo básica
// (los valores `null` y `undefined` permitirán cualquier tipo)
propA: Number,
// Múltiples tipos posibles
propB: [String, Number],
// String requerida
propC: {
type: String,
required: true
},
// String requerida pero que puede ser nula
propD: {
type: [String, null],
required: true
},
// Número con un valor predeterminado
propE: {
type: Number,
default: 100
},
// Objeto con un valor predeterminado
propF: {
type: Object,
// Los valores predeterminados de objetos o arrays deben ser devueltos
// desde una función factory. La función recibe las
// props sin procesar recibidas por el componente como argumento.
default(rawProps) {
return { message: 'hola' }
}
},
// Función validadora personalizada
// todas las props se pasan como 2do argumento en 3.4+
propG: {
validator(value, props) {
// El valor debe coincidir con uno de estos strings
return ['success', 'warning', 'danger'].includes(value)
}
},
// Función con un valor predeterminado
propH: {
type: Function,
// A diferencia del valor predeterminado de objeto o array, esta no es
// una función factory - es una función para servir como valor predeterminado
default() {
return 'Función predeterminada'
}
}
})TIP
El código dentro del argumento defineProps() no puede acceder a otras variables declaradas en <script setup>, porque toda la expresión se mueve a un ámbito de función externa cuando se compila.
Detalles adicionales:
Todas las props son opcionales por defecto, a menos que se especifique
required: true.Una prop opcional ausente que no sea
Booleantendrá un valorundefined.Las props
Booleanausentes se convertirán afalse. Puedes cambiar esto configurando undefaultpara ella, por ejemplo:default: undefinedpara que se comporte como una prop no booleana.Si se especifica un valor
default, se utilizará si el valor de la prop resuelto esundefined; esto incluye tanto cuando la prop está ausente como cuando se pasa un valorundefinedexplícito.
Cuando falla la validación de una prop, Vue producirá una advertencia en la consola (si se utiliza la versión de desarrollo).
Si se utilizan declaraciones de props basadas en tipos , Vue hará todo lo posible para compilar las anotaciones de tipo en declaraciones de prop equivalentes en tiempo de ejecución. Por ejemplo, defineProps<{ msg: string }> se compilará en { msg: { type: String, required: true }}.
Verificaciones de Tipo en Tiempo de Ejecución
El type puede ser uno de los siguientes constructores nativos:
StringNumberBooleanArrayObjectDateFunctionSymbolError
Además, type también puede ser una clase o función constructora personalizada y la aserción se realizará con una verificación instanceof. Por ejemplo, dada la siguiente clase:
js
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}Podrías usarla como el type de una prop:
js
defineProps({
author: Person
})Vue usará instanceof Person para validar si el valor de la prop author es realmente una instancia de la clase Person.
Tipo Nulo
Si el tipo es requerido pero puede ser nulo, puedes usar la sintaxis de array que incluye null:
js
defineProps({
id: {
type: [String, null],
required: true
}
})Ten en cuenta que si type es solo null sin usar la sintaxis de array, permitirá cualquier tipo.
Conversión Booleana
Las props con tipo Boolean tienen reglas de conversión especiales para imitar el comportamiento de los atributos booleanos nativos. Dado un <MyComponent> con la siguiente declaración:
js
defineProps({
disabled: Boolean
})El componente puede usarse así:
template
<!-- equivalente a pasar :disabled="true" -->
<MyComponent disabled />
<!-- equivalente a pasar :disabled="false" -->
<MyComponent />Cuando una prop se declara para permitir múltiples tipos, también se aplicarán las reglas de conversión para Boolean. Sin embargo, hay un caso límite cuando tanto String como Boolean están permitidos: la regla de conversión booleana solo se aplica si Boolean aparece antes de String:
js
// disabled se convertirá a true
defineProps({
disabled: [Boolean, Number]
})
// disabled se convertirá a true
defineProps({
disabled: [Boolean, String]
})
// disabled se convertirá a true
defineProps({
disabled: [Number, Boolean]
})
// disabled se analizará como un string vacío (disabled="")
defineProps({
disabled: [String, Boolean]
})







