n Understand Reactivity in Vue.js 3 | CodimTh

Please Disable Your Browser Adblock Extension for our site and Refresh This Page!

our ads are user friendly, we do not serve popup ads. We serve responsible ads!

Refresh Page
Skip to main content
On . By CodimTh
Category:

Understand Reactivity  in Vue.js 3

 

To create a reactive state from a JavaScript object, we can use a reactive method:

import { reactive } from 'vue'

// reactive state
const state = reactive({
  count: 0
})

 

reactive is the equivalent of the Vue.observable() API in Vue 2.x, renamed to avoid confusion with RxJS observables. Here, the returned state is a reactive object. The reactive conversion is "deep" - it affects all nested properties of the passed object.

The essential use case for reactive state in Vue is that we can use it during render. Thanks to dependency tracking, the view automatically updates when reactive state changes.

This is the very essence of Vue's reactivity system. When you return an object from data() in a component, it is internally made reactive by reactive(). The template is compiled into a render function that makes use of these reactive properties.

You can learn more about reactive in the Basic Reactivity API's section

 

Creating Standalone Reactive Values as refs

Imagine the case where we have a standalone primitive value (for example, a string) and we want to make it reactive. Of course, we could make an object with a single property equal to our string, and pass it to reactive. Vue has a method that will do the same for us - it's a ref:

import { ref } from 'vue'

const count = ref(0)

 

ref will return a reactive and mutable object that serves as a reactive reference to the internal value it is holding - that's where the name comes from. This object contains the only one property named value:

import { ref } from 'vue'

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

 

Ref Unwrapping

When a ref is returned as a property on the render context (the object returned from setup()) and accessed in the template, it automatically unwraps to the inner value. There is no need to append .value in the template:

<template>
  <div>
    <span>{{ count }}</span>
    <button @click="count ++">Increment count</button>
  </div>
</template>

<script>
  import { ref } from 'vue'
  export default {
    setup() {
      const count = ref(0)
      return {
        count
      }
    }
  }
</script>

 

Access in Reactive Objects

When a ref is accessed or mutated as a property of a reactive object, it automatically unwraps to the inner value so it behaves like a normal property:

const count = ref(0)
const state = reactive({
  count
})

console.log(state.count) // 0

state.count = 1
console.log(count.value) // 1

 

If a new ref is assigned to a property linked to an existing ref, it will replace the old ref:

const otherCount = ref(2)

state.count = otherCount
console.log(state.count) // 2
console.log(count.value) // 1

 

Ref unwrapping only happens when nested inside a reactive Object. There is no unwrapping performed when the ref is accessed from an Array or a native collection type like Map:

const books = reactive([ref('Vue 3 Guide')])
// need .value here
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// need .value here
console.log(map.get('count').value)

 

Destructuring Reactive State

When we want to use a few properties of the large reactive object, it could be tempting to use ES6 destructuring to get properties we want:

import { reactive } from 'vue'

const book = reactive({
  author: 'Vue Team',
  year: '2020',
  title: 'Vue 3 Guide',
  description: 'You are reading this book right now ;)',
  price: 'free'
})

let { author, title } = book

 

Unfortunately, with such a destructuring the reactivity for both properties would be lost. For such a case, we need to convert our reactive object to a set of refs. These refs will retain the reactive connection to the source object:

import { reactive, toRefs } from 'vue'

const book = reactive({
  author: 'Vue Team',
  year: '2020',
  title: 'Vue 3 Guide',
  description: 'You are reading this book right now ;)',
  price: 'free'
})

let { author, title } = toRefs(book)

title.value = 'Vue 3 Detailed Guide' // we need to use .value as title is a ref now
console.log(book.title) // 'Vue 3 Detailed Guide'

 

You can learn more about refs in the Refs API section

 

Prevent Mutating Reactive Objects with readonly

Sometimes we want to track changes of the reactive object (ref or reactive) but we also want prevent changing it from a certain place of the application. For example, when we have a provided reactive object, we want to prevent mutating it where it's injected. To do so, we can create a readonly proxy to the original object:

import { reactive, readonly } from 'vue'

const original = reactive({ count: 0 })

const copy = readonly(original)

// mutating original will trigger watchers relying on the copy
original.count++

// mutating the copy will fail and result in a warning
copy.count++ // warning: "Set operation on key 'count' failed: target is readonly."

Riadh Rahmi

Senior Web Developer PHP/Drupal & Laravel

I am a senior web developer, I have experience in planning and developing large scale dynamic web solutions especially in Drupal & Laravel.

Web Posts

Search

Page Facebook