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
:
<script setup lang="ts">
import { shallowRef } from 'vue'
const state = shallowRef({
count: 0,
})
</script>
<template>
<span>Count: {{ state.count }}</span>
</template>
Now let's try to modify the count value:
<script setup lang="ts">
import { shallowRef, watch } from 'vue'
const state = shallowRef({
count: 0,
})
const increment = () => {
state.value.count = 2 // ⚠️ doesn't trigger change (watcher & UI update)
}
watch(state, (newState) => {
console.log('new state', newState)
})
</script>
<template>
<span>Count: {{ state.count }}</span>
<button @click="increment">Increment count</button>
</template>
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:
<script setup lang="ts">
import { shallowRef, watch } from 'vue'
const state = shallowRef({
count: 0,
})
const setNewValue = () => {
state.value = { count: 2 } // triggers change
}
watch(state, (newState) => {
console.log('new state', newState)
})
</script>
<template>
<span>Count: {{ state.count }}</span>
<button @click="setNewValue">Set new .value</button>
</template>
shallowRef()
is typically used for performance optimizations of large data structures, or integration with external state management systems.
Try it yourself in the following StackBlitz project:
If you liked this Vue tip, follow me on Twitter to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue newsletter: