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>
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.
If you liked this Vue tip, follow me on BlueSky to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter :
Vue Tip: Declare and Mutate v-model Props as Normal Variable Using defineModel
Nuxt Tip: Render Component Only on Client-Side