Featured image of post Vue 3 Knowledge You Might Not Know

Vue 3 Knowledge You Might Not Know

Dynamically Binding Multiple Values in Templates

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<template>
  <div v-bind="objectOfAttrs"></div>
</template>

<script setup>
  const objectOfAttrs = {
    id: 'container',
    class: 'wrapper',
    style: 'background-color:green'
  }
</script>

Dynamic Parameters

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<template>
  <!-- Dynamic event binding -->
  <button @[eventName]="handle">Dynamic Event Binding</button>
  <!-- Dynamic attribute binding -->
  <HelloWorld :[attributeName]="HelloWorld"/>
</template>

<script setup>
import { ref } from 'vue'
const attributeName = ref('msg')
const eventName = ref('click')
const handle = () => {
  console.log('Dynamic event triggered')
}
</script>

Iterating Over Objects with v-for

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<template>
  <ul>
    <li v-for="(value, key, index) in myObject">
      {{ index }}. {{ key }}: {{ value }}
    </li> 
  </ul>
</template>

<script setup>
import { reactive } from 'vue'
const myObject = reactive({
  title: 'How to do lists in Vue',
  author: 'Jane Doe',
  publishedAt: '2016-04-10'
})    
</script>

Using a Range with v-for

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<template>
  <ul>
    <li v-for="n in 10">{{ n }}</li>
  </ul>
</template>

/*
  Output:
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
*/

Watching Multiple Data Sources

1
2
3
4
5
6
7
8
9
<script setup>
import { watch, ref } from 'vue'
const x = ref(0)
const y = ref(1)

watch([x, y], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})
</script>

Watch Can’t Directly Observe Reactive Object Properties

When using watch, the first parameter should be a reactive object or a function that returns a reactive object. This restriction ensures Vue’s reactivity system can properly track changes using Proxy getters.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const obj = reactive({ count: 0 })

// This won't work because we are passing a number to watch()
watch(obj.count, (count) => {
  console.log(`Count is: ${count}`)
})

// Instead, use a getter:
watch(
  () => obj.count,
  (count) => {
    console.log(`Count is: ${count}`)
  }
)

Accessing Updated DOM in watch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
watch(source, callback, {
  flush: 'post'
})
// or
watchEffect(callback, {
  flush: 'post'
})
// or
watchPostEffect(() => {
  /* executed after Vue updates */
})

Stopping a Watcher

1
2
3
4
const unwatch = watchEffect(() => {})

// ...later, when no longer needed
unwatch()

For more details on watch, you can refer to this blog.

Function Template References

The ref attribute can bind to a function, which is called whenever the bound component updates. This method provides more flexibility in obtaining element references. The function receives the element reference as the first argument:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<template>
  <input type="text" :ref="getRef">
  <test-cpn :ref="getRef"/>
</template>

<script setup>
const getRef = (el) => {
  console.log(el); // Direct DOM element if it's an element
  if(el) {
    console.log(el.$el); // Component instance if it's a component
  }
}
</script>

Note: The argument will be null after the element is removed.

Using ref with v-for

The ref attribute can also be used with v-for to bind multiple elements/component instances generated by v-for. The value of the corresponding ref object will be an array.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<template>
  <ul>
    <li v-for="item in list" ref="itemRefs">
      {{ item }}
    </li>
  </ul>
</template>

<script setup>
import { ref, onMounted } from 'vue'
const list = ref([
  /* ... */
])
const itemRefs = ref([])
onMounted(() => console.log(itemRefs.value))
</script>

Note: The order of elements in the array is not guaranteed to match the iteration order.

Component Instance References

You can also use template references to get a child component’s instance. However, this depends on whether the child component uses the Options API or <script setup>.

If a child component uses the Options API or does not use <script setup>, the parent component has full access to all the child component’s properties and methods.

If a child component uses <script setup>, it is private by default: the parent component cannot access anything within the child component.

For the second case, the child component must explicitly expose properties or methods using the defineExpose macro.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)
// Compiler macros, such as defineExpose, don't need to be imported
defineExpose({
  a,
  b
})
</script>

withDefaults Helper Function

The withDefaults helper function is a utility that helps set default values for component props when defining them. This ensures that props have a preset default value if no value is passed. This can simplify the code, avoiding the need to manually set default values for each prop.

Moreover, since withDefaults can help define the types and default values of props, TypeScript can correctly infer and check the usage of the component’s props.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const props = withDefaults(defineProps({
  message: String,
  count: { type: Number, default: 0 },
}));

// or
const props = withDefaults(defineProps<{
  message: string,
  count: number,
}>(), {
  message: 'hello',
  count: 0
})