Subscribe on changes!

The array passed after using defineMdel will lose its responsiveness

avatar
Jan 10th 2024

Vue version

3.4.7

Link to minimal reproduction

https://play.vuejs.org/#eNqFU01v2kAQ/SurvZhIxBxyswxKk3JopbSo7Y3NwZgBHMyuu7smRBb/vTNj/AEh6QW8b958vZmp5JeiCPclyEjGLrVZ4YUDXxYTpbNdYawXlbCwGorXxKcbcRQra3YiQI+gZTy9PRr80qD9yRyOehiFR7LSqdEOGcaIMcUczJ9vGnCR2D7YwJtEL3OY7jKP1sE+yUu4EeOJqJQW5BMyhDb+V/pIrvGobgRbwIeHXZEnHvAlKHckqoprOCKZgzBCBdRIvLDMjftt7W93Zgl5hI5jJfFXSRGRzz1gce4WPxHvykXzCKPEoza9HMoLTf4jeaO1kshV8lLAJawyDU9U1SBAKBjWqlj4W2YWlpHwliXpyVlYU7jWd0avwTzA2oNuEtxPy6FeiMPowxmxGxmHDfH9bnJfuyJnpds85lm6pUl2Q8TK2yHOn8+QsECXQSW28BaJoHTQ7zkQ1BjPu5+Qe/ogVX9f6lQt8j4V91QnISb3P+hkGHa+TRmfLl68KL03WtynVFe7Ktf0UXJy0Ws8qr1PkU7reT3iuQCnWAz2opyvpXeo4Cpbhy/OaFxKFkvJFHc1y8H+LHyGCiuJd0IWsiV5bl6/M0ZbNmzwdAPp9gr+4g6EKTmz4MDucZ9bm0/sGvBgyDz9/QMO+N0a8erKHNmfGH+BM3lJNda0h5J0sD0eV/uNTyvT6z9uevCgXdNUfSZCHJnP10Zn+lHrXbl34R374fzl8R+/2NGi

Steps to reproduce

Step 1: Create an empty array, Step 2: Use defineModel to pass to child components, Step 3: Then after the subcomponent performs data operations, Step 4: The parent component displays the data

What is expected?

Display the data after operation

What is actually happening?

Displayed as empty array

System Info

No response

Any additional comments?

The official website recommends using defineModel after 3.4, but the test found that the data cannot be displayed. Using controlled experiments, we found that props transfer can successfully display correct data.

avatar
Jan 10th 2024

After testing, it was found that if the array is not cleared when clicking, the data can be displaye demo d correctly.

avatar
Jan 10th 2024

In reality, after assigning foo.value = [], the updated value of foo.value can only be accessed in the child component after the next execution of the render function. Therefore, when you use foo.value.push({/**/}), you are actually pushing onto the old foo.value rather than the new one. After the child component is updated, foo.value will have the new value, which is an empty array. You should perform the assignment after the push operation, once the child component update is complete.

playground

const foo = defineModel('foo', {
  required: true
})

const handleDefineModelPushClick =  () => {
  const arr = []
  arr.push({ key: 'use defineModel' })
  foo.value = arr
}
avatar
Jan 10th 2024

When you keep in mind that defineModel() is a convenience shortcut for the following, it becomes more appearant:

const props = defineProps(['modelValue'])
const emits = defineEmits(['update:modelValue'])

// you basically did this:
emit('update:modelValue', [])
props.modelValue.push(....)
avatar
Jan 10th 2024

In reality, after assigning foo.value = [], the updated value of foo.value can only be accessed in the child component after the next execution of the render function. Therefore, when you use foo.value.push({/**/}), you are actually pushing onto the old foo.value rather than the new one. After the child component is updated, foo.value will have the new value, which is an empty array. You should perform the assignment after the push operation, once the child component update is complete.

playground

const foo = defineModel('foo', {
  required: true
})

const handleDefineModelPushClick =  () => {
  const arr = []
  arr.push({ key: 'use defineModel' })
  foo.value = arr
}

感谢