Vue 3: Common Options API things done the Composition way
Drew Clements
Posted on June 3, 2022
As with all things new
For those living under a rock (or buried under legacy spaghetti), Vue 3 dropped in 2021 and in February of 2022 it was declared the default version moving forward. With it came the new composition API. The composition API brings a lot of changes in how we write, structure, and build Vue components.
This article is going to be looking at some of the more commonly used Vue features and what they look like in Vue 3, compared to their Vue 2 counterparts.
What we'll be looking at:
- props
- methods
- data
- computed properties
- watchers
Props
Props are probably one of the most used features in Vue- or any framework really. Props are what allow passing data, whether it be static or dynamic, from component to component.
A common pattern is to define what props a component will be receiving, for a variety of reasons. Define types, whether or not it's required, and more importantly just so the component is aware of it and can be accessed in the template.
Here's what registering props in Vue 2 looks like:
<script>
export default {
props: {
myProp: {
type: String,
default: "Hello",
}
}
}
</script>
There's nothing overly complicated about it. In fact, prop registration has never been a "difficult" thing in Vue.
Here's what registering props looks like in Vue 3:
<script setup>
const props = defineProps({
myProp: {
type: String,
default: "Hello",
}
})
</script>
And both of these would be available in the template like so:
<template>
<p>{{ myProp }}</p>
</template>
Methods
In Vue 2, methods are where you would store functions for a component you would call elsewhere- either from the template or other lifecycle hooks: computed properties, watchers, mounted, etc.
The concept of methods doesn't exist in the context of script setup
. You simply write the function you need and it's available!
Let's look at the Vue 2 way of doing this:
<script>
export default {
methods: {
doTheThing() {
console.log("The Thing")
}
}
}
</script>
And in Vue 3:
<script setup>
function doTheThing() {
console.log("The Thing")
}
</script>
And both of these would be available in the template like so:
<template>
<button type="button" @click="doThething">Click me</button>
</template>
Data
In Vue 2, there's a concept of the data object which is where you can define data points to use in your component as needed. These could be strings, arrays, objects- you name a data type and it can live here (within reason). Forgive my definition of it- this is how I explain it to myself. Think of it "state" for the component.
Here's the Vue 2 way:
<script>
export default {
data() {
return {
myText: 'Hello, I R Text'
}
}
}
</script>
There's actually two ways to accomplish this in Vue 3, with a ref or a reactive.
Reactive
Reactive objects are JavaScript Proxies and behave just like normal objects. The difference is that Vue is able to track the property access and mutations of a reactive object.
-Vue Docs
This is what a Reactive looks like in Vue 3:
<script setup>
import { reactive } from 'vue'
const state = reactive({count: 0})
console.log(state.count)
</script>
This would be available in the template like so:
<template>
<p>{{ state.count }}</p>
</template>
There are some limitations to reactives. Check out the docs to learn more about what those are.
Ref
To address the limitations of reactive(), Vue also provides a ref() function which allows us to create reactive "refs" that can hold any value type
-Vue docs
Here's what a ref looks like in Vue 3:
<script setup>
import { ref } from 'vue';
const count = ref(0)
console.log(count.value)
</script>
And this would be available in the template like so:
<template>
<p>{{ count }}</p>
</template>
Computed Properties
The concept of computed properties in Vue is to give you a way to "handle complex logic that includes reactive data" (official Vue documentation).
Let's say you want to display either the word 'open' or 'closed' depending on the time of day. That would be a lot of logic to cram into the template.
Let's look at what that would look like in a Vue 2 computed property:
// for brevity's sake we're going to pretend a data property isBeforeFive and isWeekend exists and returns true or false
<script>
export default {
computed: {
isOpen() {
return isBeforeFive && !isWeekend ? 'Open' : 'Closed';
}
}
}
</script>
Obviously this example is a little contrived, but you get the idea here.
Here's that same thing in Vue 3:
<script setup>
import { computed } from 'vue';
const isOpen = computed(() => {
return isBeforeFive && !isWeekend ? 'Open' : 'Closed';
}
</script>
Both of these would be available in the template like so:
<template>
<p>{{ isOpen }}</p>
</template>
Watchers
Last but not least of what we're covering today are watchers. Watchers can be an extremely useful tool in the arsenal because they allow you 'to perform "side effects" in reaction to state changes'(official Vue Documentation).
For example: let's say we want to trigger an alert anytime a counter is updated.
Here's that in Vue 2:
<script>
export default {
data() {
return {
count: 0
},
watch: {
count(newVal, oldVal) {
if(newVal > oldVal) alert('Count ticked up!')
}
}
}
</script>
Here it is in Vue 3:
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
watch(count, (newVal, oldVal) => {
if(newVal > oldVal) alert('Count ticked up!')
})
</script>
Each of these will trigger an alert anytime the new value of count
goes up.
Summary
Vue 3 seems like it's going to be a lot of fun. I can see where the simplicity of script setup
will come in handy- but I'm also a huge creature of habit and I like how my Options API has kept things organized for me.
I used to ask "what's an edge case in which I should use composition over options?" After diving into it in more depth, to me, the answer is that there isn't an edge case that will ever force your hand into one or the other and that each has their merits.
Decide for yourself which one you prefer and use that one.
The Vue team has done an amazing job building a useful framework from the beginning and the composition API is just the next iteration of their efforts.
Posted on June 3, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.