Unlocking Vue 3's defineModel Macro: Eliminate Prop Mutation Worries


Vue 3's custom v-model options: 'modelValue' vs. 'defineModel'. Which would you choose?

In the past, setting up two-way data binding between components was a somewhat manual process, compounded by the immutability of props. This meant that extra caution was needed when dealing with props drilling, as inadvertent modifications by child components could lead to loss of reactivity. You had to define properties and events, ensuring to emit them or reactivity is lost. Discover how Vue 3.4's new defineModel compiler macro simplifies this process and allows props mutations.

Example: Prior to defineModel() compiler macro was introduced in Vue 3.4

<!-- MyComponent.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="props.modelValue"
    @input="emit('update:modelValue', $event.target.value)"
  />

<!-- pass the prop -->
<MyComponent v-model="count" />


Example: implement the same MyComponent.vue shown above in Vue 3.4

With Vue 3.4, the introduction of the defineModel compiler macro significantly streamlines this process. For example, we can achieve the same outcome as the above example using defineModel exclusively.

<!-- MyComponent.vue -->
<script setup>
const model = defineModel()
</script>

<template>
  <input v-model="model" />
</template>

<!-- pass the prop -->
<MyComponent v-model="count" />

The value from defineModel() is a ref object, similar to any other ref object created using ref() method, but with a unique feature: it facilitates a two-way binding between parent and child component.

  • Its .value is synchronized with the parent's v-model-bound value.
  • If altered by the child, it automatically updates the parent-bound value. Say goodbye to the hassle of using emit('update:modelValue', $event.target.value)

This also allows child component to pass props data to other components (Props drilling) without worrying about underlying mutation.


What is difference?

defineModel simplifies the process of creating two-way binding between parent and child components by automatically generating the necessary props and events. Instead of manually defining the modelValue prop and emitting the update:modelValue event, you can use defineModel to handle these tasks for you. This reduces the amount of boilerplate code you need to write and makes your components cleaner and more concise.


How to use custom prop name with defineModel() ?

To use a custom prop name or multiple v-models, you'll need to specify an identifier as an argument, such as v-model:title previously. The same customization can be achieved with defineModel.

Example:

<!-- MyComponent.vue -->
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>

<template>
  <input type="text" v-model="firstName" />
  <input type="text" v-model="lastName" />
</template>


<!-- pass the prop -->
const first = ref('Akram');
const last = ref('Wahid');

<MyComponent
  v-model:first-name="first"
  v-model:last-name="last"
/>


In conclusion,

While the defineModel macro may appear simple, those familiar with managing multiple component bindings understand the tediousness of manual upkeep. Vue once again streamlines our workflow, easing the burden of component synchronization.


If you have any other questions, experience or insights on "How to use Vue 3.4 defineModel() compiler macro" please feel free to leave your thoughts in the comments bellow, Don't forget to share the posts.
Written by Akram Wahid 8 months ago

are you looking for a chief cook who can well craft laravel and vuejs, to make some awsome butterscotch,
yes then it is right time for you to look at my profile.

Do you want to write Response or Comment?

You must be a member of techalyst to proceed!

Continue with your Email ? Sign up / log in

Responses

Be the first one to write a response :(

{{ item.member.name }} - {{ item.created_at_human_readable }}

{{ reply.member.name }} - {{ reply.created_at_human_readable }}