Must-Know Property Creation Differences in Vue 2 and Vue 3

Last modified on October 29th, 2020
Raja Tamil
Vue.js

I’m going to show you how to create a property in Vue 2 using Options API, Then I am going to show you how to create it in Vue 3 using Composition API.

Then, you’re going to learn how to create properties using wrapper objects ref and reactive, when to use them and why.

By the end of this article, you’ll be able to understand the property creation differences between Vue 2 Options API vs Vue 3 Composition API.

Sounds interesting…Let’s get started!

Define A Property Using Options API Vue 2

One of the ways to declare properties in Options API, introduced in Vue 2, is to have them added to the JavaScript object that the data() function returns.

As you can see, I’ve created a name property and set its initial value to null.

export default {
  data() {
    return {
      name: null
    }
  }
}

When we create a property using Options API, it becomes reactive by default.

Reactive?

The name property is reactive meaning it can be bound to an HTML element in the template.

Whenever the property values change, the view gets updated and vice versa, which is also called two-way data binding.

All the properties that we declare in the Options API are reactive which can be good most of the time.

Access The Property in JavaScript Vue 2

To access the name property anywhere inside the export default object in this component, we can use this keyword in the Options API.

Let’s say I want to access it inside the mounted() function which is one of the lifecycle methods in Options API.

export default {
  ...
  mounted() {
    console.log(this.name);
  }
}

Let’s see how to access the name property in the Vue template.

Access The Property in the Vue 2 Template

Whenever we create properties using Options API, they are not only reactive but also become immediately available to the Vue template.

So, we can simply use double curly braces to access the name property in between the template tags.

<template>
  <div>
    {{name}}
  </div>
</template>

In Vue 2, inside the template tags, we need to have one parent element in which all other elements will go in.

You may know this process already but let’s see how to do that using the new Composition API.

Composition API (Vue 3)

One of the great things about Vue 3 is that we can literally use Options API to create reactive properties like in the example above and it’ll just work like a charm.

Additionally, we can now use Composition API to create properties that are very flexible and you can see why just in a moment.

There are two ways to create reactive properties in Vue 3 which are:

  • ref
  • reactive

ref()

In Vue 3, we need to import any package that we want to use in our app.

This way we only include the package that we use in the production bundle which makes the app lighter and faster.

<script>
  import { ref } from "vue";
  export default {
     setup() {
       // all of your variables and function will go here
     }
  } 
</script>

With Composition API, all of the properties and functions will go inside the setup() method of the export default object.

<script>
  import { ref } from "vue";
  export default {
     setup() {
       let name = ref("");
     }
  } 
</script>

In there, we can create properties as a variable using let or const or var (not recommended) keywords.

On the right side, the value of the name variable is an empty string wrapped with the ref object.

So what is ref() object? 🤷‍♂️

A ref is a wrapper object that takes an inner value and returns a reactive and mutable object.

We can assign it to a variable with an initial value inside the parentheses…in this case a pair of double-quotes.

So why do we need it?

It keeps the reactivity when the value of the name variable changes by emitting a reactive event so the observers can be updated automatically.

It takes an inner value and returns a reactive and mutable object.

Now the name variable is a type of ref object wrapped with a value inside.

Access The Ref() Variable In JavaScript

To get the value associated with the name variable, we just need to unwrap it using the .value property of it which will then give the value.

The ref() object will have a single property called .value that points to the inner value.

<script>
  import { ref } from "vue";
  export default {
     setup() {
       let name = ref("Raja");
       name.value = Raja Tamil; // Set
       console.log(name.value) // Get
     }
  } 
</script>

Yes, when you want to set a value to the name variable, we need to use .value as well.

As you know, in Vue 2 with Options API, all the properties become available in the template as soon as they are created.

But in Vue 3 with Composition API, we have an option to explicitly expose the properties and function to the template.

This means we can now create a variable that is private which can be only accessed inside the setup() function.

Now, all we need to do is add this variable as a property in a JavaScript object that the setup() function returns.

<script>
  import { ref } from "vue";
  export default {
     setup() {
       let name = ref("Raja");
       return {
          username: name
       }
     }
 } 
</script>

The returned object has one property which is a username and the value is the name that is declared above.

Coming from Vue 2, this is one of the things I often forget to add the variable as a property to the returned object. 😉

Most of the time, you want the key and value of the property to be the same for maintainability purposes.

return {
  name:name
}

To simplify this, Use object property value shorthand like this.

return {
  name
}

Access The Property In The Vue 3 Template

In the template, use double curly braces to access the name property which is similar to Options API.

<template>
   {{name}}
</template>

So what happened to the parent div?

In Vue 3, we no longer need a parent div 🙂

Now we can have div elements that are siblings right inside the template tags.

Reactive()

The other way of creating variables in Composition API is by using reactive() which is a wrapper object.

You may wonder…

Why would we need two ways of creating variables in Vue 3?

Well, ref() is for a single variable with a primitive type, such as string, number, etc and it keeps the reactivity when the value changes.

As soon as we create a variable that has dictionary-structured data like an object, the ref loses its reactivity.

For that, we need a reactivity() wrapper object instead of a ref() object.

Reactive() takes an object and returns a reactive proxy of the original object.

Let see how to do that.

Import reactive package from Vue.

import { reactive } from "vue";

Similar to ref, use a reactive wrapper object and pass a Javascript object as an initial value to a variable.

<script>
  import { reactive } from "vue";
  export default {
     setup() {
       let book = reactive({title: "The Best Vue 3 Book", price:19.99});
     }
 } 
</script>

Get The Value From The Reactive() Variable

The good news is that we do not have to use .value to unwrap the value of the book variable, unlike ref.

<script>
  import { reactive } from "vue";
  export default {
     setup() {
       let book = reactive({title: "The Best Vue 3 Book", price:19.99});
       console.log(book.title);
       console.log(book.price);
     }
 } 
</script>

We can directly access properties of the book object as we normally do.

Access The Property In The Vue 3 Template

Similar to the previous example, all we need to do is to add this variable as a property in a JavaScript object that the setup() function returns.

<script>
  import { reactive } from "vue";
  export default {
     setup() {
       let book = reactive({title: "The Best Vue 3 Book", price:19.99});
       return {
         book
       }
     }
 } 
</script>

And we can access it in the template using double curly braces as usual.

<template>
  {{book.title}}
  {{book.price}}
</template>

To check the reactivity, change the value of both properties after 2 seconds using setTimeout() function.

<script>
  import { reactive } from "vue";
  export default {
     setup() {
       let book = reactive({title: "Vue 3 Book", price:29.99});
        
       setTimeout(() => {
          book.title = "Vue 3 is awesome";
          book.price = 19.99;
       }, 2000)
       
       return {
         book
       }
     }
 } 
</script>

You will be able to see that the reactivity works by seeing the value changes after 2 seconds in the template.

So What About Arrays?

Arrays are one of the types that we can make reactive by using either ref or reactive wrapper objects.

I would use reactive over ref where possible to avoid .value syntax

Variable Without Reactivity

The other great thing about Vue 3, we can now create a variable that can be private as well as non-reactive when needed.

<script>
  import { reactive } from "vue";
  export default {
     setup() {
       let book = {title: "Vue 3 Book", price:29.99};
       return {
         book
       }
     }
 } 
</script>

Here Is The Recap:

Reactivity

In Vue2 (Options API)
All the properties declared in the data() function will be reactive.

In Vue3, (Composition API)
Properties can be declared reactive or non-reactive and for the reactivity using two wrapper objects ref and reactive.

ref is for single variables.
reactive is for dictionary-structured variables.

Template

In Vue2 (Options API)
All the elements must go inside a single parent element inside template tags.

In Vue3, (Composition API)
Multiple elements can be created as siblings inside template tags.

Scope

In Vue2 (Options API)
All the properties declared in the component using Options API will become immediately available to use inside the template.

In Vue3, (Composition API)
We need to explicitly return variables that we want to expose into an object as properties.

Hope you like this article and let me know if anything is unclear or if I missed anything.

Happy Coding.