Vue Tip: Optimize Performance Using shallowRef
shallowRef can be used to optimize the reactivity of your Vue application. As you might have guessed, shallowRef
is a shallow version of ref().
Let's start by defining a counter state using shallowRef
:
1<script setup lang="ts">
2import { shallowRef } from 'vue'
3
4const state = shallowRef({
5 count: 0,
6})
7</script>
8
9<template>
10 <span>Count: {{ state.count }}</span>
11</template>
Now let's try to modify the count value:
1<script setup lang="ts">
2import { shallowRef, watch } from 'vue'
3
4const state = shallowRef({
5 count: 0,
6})
7
8const increment = () => {
9 state.value.count = 2 // ⚠️ doesn't trigger change (watcher & UI update)
10}
11
12watch(state, (newState) => {
13 console.log('new state', newState)
14})
15</script>
16
17<template>
18 <span>Count: {{ state.count }}</span>
19 <button @click="increment">Increment count</button>
20</template>
Be careful
If you click the "Increment count" button the counter in the UI is not updated and the watcher is not fired.
Unlike ref()
, the inner value of a shallow ref is stored and exposed as-is, and will not be made deeply reactive. Only the .value
access is reactive.
The reactivity is correctly triggered if we pass a complete new value to the .value
property:
1<script setup lang="ts">
2import { shallowRef, watch } from 'vue'
3
4const state = shallowRef({
5 count: 0,
6})
7
8const setNewValue = () => {
9 state.value = { count: 2 } // triggers change
10}
11
12watch(state, (newState) => {
13 console.log('new state', newState)
14})
15</script>
16
17<template>
18 <span>Count: {{ state.count }}</span>
19 <button @click="setNewValue">Set new .value</button>
20</template>
shallowRef()
is typically used for performance optimizations of large data structures, or integration with external state management systems.
Info
Try it yourself in the following StackBlitz project:
If you liked this Vue tip, follow me on X to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter:
Nuxt Tip: Render Component Only on Client-Side
By default, Nuxt uses universal (client-side + server-side) rendering to render your application. The ClientOnly component can be used torender its slot only in client-side.
Vue Tip: Declare and Mutate v-model Props as Normal Variable Using defineModel
Declaring and mutate v-model props as the same as normal variable using the defineModel.