Skip to content
← Todas las preguntas
⚡ Intermedio

¿Por qué mutar un objeto a través de defineModel no actualiza al padre?

🧩 Componentes❌ Errores comunes🔄 v-model

Porque defineModel() solo emite update:modelValue cuando reasignas model.value en sí mismo. Mutar una propiedad dentro del objeto (model.value.name = 'x') cambia el objeto en su lugar sin cambiar la referencia, por lo que Vue nunca dispara el evento update:modelValue. Los watchers del padre sobre el binding v-model no detectan el cambio, aunque el template del padre sigue reflejando la mutación porque ambos lados comparten el mismo objeto reactivo.

vue
<script setup>
const model = defineModel<{ name: string; age: number }>()

function updateName(newName: string) {
  model.value.name = newName // el padre nunca se entera
}
</script>
Open in Vue Playground

Cómo solucionarlo

Reemplaza el objeto completo para que la referencia cambie y el evento se dispare.

ts
function updateName(newName: string) {
  model.value = { ...model.value, name: newName }
}

Para arrays, la misma idea:

ts
function addItem(item: string) {
  model.value = { ...model.value, items: [...model.value.items, item] }
}

Las actualizaciones profundas se vuelven verbosas

ts
// Actualización profundamente anidada
model.value = {
  ...model.value,
  user: {
    ...model.value.user,
    address: { ...model.value.user.address, city: 'Madrid' }
  }
}

// structuredClone es más limpio para objetos complejos
function updateCity(city: string) {
  const updated = structuredClone(model.value)
  updated.user.address.city = city
  model.value = updated
}

Evita emisiones dobles innecesarias

Cuando actualices varios campos, agrúpalos en una sola asignación. Dos spreads consecutivos leen el model.value correcto (las asignaciones a refs son síncronas), pero cada uno crea una nueva referencia de objeto, emitiendo update:modelValue dos veces. Esto es innecesario y puede causar re-renders del padre.

ts
// funciona, pero emite update:modelValue dos veces
model.value = { ...model.value, a: '1' }
model.value = { ...model.value, b: '2' }

// mejor: asignación única, una sola emisión
model.value = { ...model.value, a: '1', b: '2' }

Ver también: ¿Cómo funciona v-model en componentes personalizados? · ¿Cómo funcionan los bindings múltiples de v-model? · ¿Por qué mutar props causa warnings?

Referencias

Publicado bajo la licencia MIT.