Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/define-model-default-value-sync.md
1---2title: defineModel Default Value Can Cause Parent-Child Desync3impact: HIGH4impactDescription: Default values in defineModel don't sync back to parent, causing state inconsistency5type: capability6tags: [vue3, v-model, defineModel, components, props, two-way-binding]7---89# defineModel Default Value Can Cause Parent-Child Desync1011**Impact: HIGH** - When using `defineModel()` with a default value and the parent doesn't provide a value, the parent and child components will have different values. The parent's ref stays `undefined` while the child uses the default, breaking the two-way binding contract.1213This subtle bug can cause confusing behavior where the parent component shows one value while the child shows another, and updates may not propagate correctly.1415## Task Checklist1617- [ ] Always provide initial values from the parent when using v-model18- [ ] Don't rely on defineModel defaults as the primary source of truth19- [ ] If defaults are needed, also set them in the parent component20- [ ] Test components with and without v-model props provided2122**Problem - Parent and child out of sync:**23```html24<!-- ChildComponent.vue -->25<script setup>26// Default value of 1 if parent doesn't provide value27const model = defineModel({ default: 1 })28</script>2930<template>31<input v-model="model" type="number">32<!-- Shows: 1 (from default) -->33</template>34```3536```html37<!-- ParentComponent.vue -->38<script setup>39import { ref } from 'vue'40import ChildComponent from './ChildComponent.vue'4142// PROBLEM: Parent ref is undefined, not synced with child's default43const myValue = ref() // undefined44</script>4546<template>47<ChildComponent v-model="myValue" />4849<!-- DESYNC: Child shows 1, but parent shows undefined -->50<p>Parent value: {{ myValue }}</p> <!-- Shows: undefined -->5152<!-- Even after child changes value, parent may not update correctly -->53</template>54```5556**Solution 1 - Always provide initial value from parent:**57```html58<!-- ParentComponent.vue -->59<script setup>60import { ref } from 'vue'61import ChildComponent from './ChildComponent.vue'6263// CORRECT: Parent provides the initial value64const myValue = ref(1) // Match the expected default65</script>6667<template>68<ChildComponent v-model="myValue" />69<p>Parent value: {{ myValue }}</p> <!-- Shows: 1, stays in sync -->70</template>71```7273**Solution 2 - Child emits default on mount (if parent control not possible):**74```html75<!-- ChildComponent.vue -->76<script setup>77import { onMounted } from 'vue'7879const model = defineModel({ default: 1 })8081// Sync default value back to parent on mount82onMounted(() => {83if (model.value === 1) { // Is using default84// Force emit to sync parent85model.value = 186}87})88</script>8990<template>91<input v-model="model" type="number">92</template>93```9495**Solution 3 - Use required prop or explicit undefined handling:**96```html97<!-- ChildComponent.vue -->98<script setup>99import { computed } from 'vue'100101// Mark as required - TypeScript will warn if not provided102const model = defineModel({ required: true })103104// Or handle undefined explicitly105const safeModel = computed({106get: () => model.value ?? 1, // Provide fallback107set: (val) => { model.value = val }108})109</script>110111<template>112<input v-model="safeModel" type="number">113</template>114```115116**Best Practice - Document expected initial values:**117```html118<!-- ChildComponent.vue -->119<script setup>120/**121* @prop modelValue - The numeric value (parent should initialize to 1 or desired default)122*/123const model = defineModel({124type: Number,125default: 1,126// Adding validator helps catch issues in development127validator: (value) => {128if (value === undefined) {129console.warn('ChildComponent: v-model value is undefined. Provide initial value from parent.')130}131return true132}133})134</script>135```136137## Reference138- [Vue.js Component v-model](https://vuejs.org/guide/components/v-model.html)139- [Vue School - defineModel Guide](https://vueschool.io/articles/vuejs-tutorials/v-model-and-definemodel-a-comprehensive-guide-to-two-way-binding-in-vue-js-3/)140