Skip to content
← Todas las preguntas
Principiante

¿Cuál es la diferencia entre props y estado en Vue?

ComponentesReactividad

Las props son datos que se pasan hacia abajo desde un componente padre. El estado (datos reactivos locales) es datos que el componente posee y gestiona él mismo. La diferencia clave: las props son de solo lectura, el estado es de lectura y escritura. El estado se declara con ref o reactive.

vue
<!-- Parent.vue -->
<template>
  <UserCard :name="userName" :role="userRole" />
</template>

<script setup>
import { ref } from 'vue'
const userName = ref('Ana')
const userRole = ref('Developer')
</script>
vue
<!-- UserCard.vue -->
<script setup>
// Props: recibidas del padre, solo lectura
const props = defineProps<{
  name: string
  role: string
}>()

// Estado: propiedad de este componente, lectura y escritura
const isExpanded = ref(false)
</script>

<template>
  <div>
    <h2>{{ name }} ({{ role }})</h2>
    <button @click="isExpanded = !isExpanded">
      {{ isExpanded ? 'Collapse' : 'Expand' }}
    </button>
    <p v-if="isExpanded">Profile details here...</p>
  </div>
</template>

Comparativa

PropsEstado
Quién lo controlaEl padreEl propio componente
MutableNo (solo lectura)
Se declara condefinePropsref() / reactive()
Flujo de datosDe padre a hijo (unidireccional)Interno
Dispara re-renderSí, cuando el padre cambia el valorSí, cuando el componente lo cambia

Por qué las props son de solo lectura

Vue impone el flujo de datos unidireccional. Si un hijo pudiera modificar sus props, el estado del padre cambiaría sin que el padre lo supiera, haciendo el flujo de datos impredecible y los bugs difíciles de rastrear.

ts
// Esto dispara un aviso en tiempo de ejecución
props.name = 'New name' // [Vue warn]: Attempting to mutate prop "name"

Cuando el hijo necesita cambiar un valor que pertenece al padre, debe emitir un evento:

vue
<!-- Child -->
<script setup>
const props = defineProps<{ count: number }>()
const emit = defineEmits<{ update: [value: number] }>()
</script>

<template>
  <button @click="emit('update', count + 1)">+1</button>
</template>

<!-- Parent -->
<Counter :count="total" @update="total = $event" />

Cuándo usar cada uno

EscenarioUsar
Configuración pasada desde el padre (label, color, size)Props
Toggle de UI local al componente (abierto/cerrado, hover)Estado
Valor de input compartido con el padreProps + emit (o v-model)
Datos obtenidos dentro del componenteEstado
Datos obtenidos por el padre y mostrados por el hijoProps

Ver también: ¿Puedes inicializar el state con el valor de una prop? · ¿Cómo funciona el sistema de reactividad de Vue 3?

Referencias

Publicado bajo la licencia MIT.