DEV Community

Cover image for Vue 3 Options to Composition API Migration
Mikhail Karan
Mikhail Karan

Posted on

Vue 3 Options to Composition API Migration

When the Vue3 'request for change' came out, one major change was accounted. A new API for writing the logic and handling the lifecycle of your Vue applications, called the composition API. It greatly differed from the familiar Options API that so many grew to love. This started a bit of a controversy which led to the Vue Team leaving support for the Options API in Vue3. They of course moved forward with composition but made it optional.

This leads to both being fully supported and a great experience for people migrating from Vue 2 to Vue 3, allowing for gradual component to component refactoring.

Benefits of composition API vs options API

  • Keep functionality blocks together
  • Better performance
  • Easier to extract and import logic
  • Cleaner code

For more indepth information on composition API read through the Vue.js Docs

Here's an example migration from Options API to Composition API

First lets take a look at the component we'll be converting

Options API:

<template>
  <div id="app">
    <h2>{{date}}</h2>
    <p>I drank {{cupsOfWater}} cups of water today 🥤</p>
    <button @click="drinkCup">Drink a cup</button>
    <p v-if='cupsOfWater > 0'>I drank the last cup at {{lastCup}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      cupsOfWater: 0,
      date: '',
      lastCup: ''
    };
  },
  methods: {
    drinkCup() {
      this.cupsOfWater++
    }
  },
  watch: {
    cupsOfWater: function (val) {
      this.lastCup = new Date().toTimeString()
    }
  },
  mounted(){
    this.date = new Date().toDateString()
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

Options Codepen

This is just a simple app which allows you to track how many cups of water you drink a day

The lifecycle hooks are clearly seen here, and completely separated out. Leaving you to reason out what functionality and variables go together. Although in a small app this is fairly easy to see, in a larger codebase, it can get quite complicated.

To start the migration from Options to Composition we add the setup function, which is the only hook required in the composition API.

setup(){
}
Enter fullscreen mode Exit fullscreen mode

Then lets move the cupsOfWater declaration and drinkCup() incrementing function to setup()

import {ref} from 'vue'
setup(){
    const cupsOfWater = ref(0)
    function drinkCup(){
      cupsOfWater.value++
    }

    return {
      cupsOfWater,
      drinkCup
    }

}
Enter fullscreen mode Exit fullscreen mode

Lets break down what we just did

  • imported the ref functionality to show that a variable is meant to be reactive
  • declared cupsOfWater as a reactive variable with a initial value of 0
  • created a new function called drinkCup() which increments our reactive cupsOfWater variable, .value is required to access and change the value of reactive variables
  • returned cupsOfwater and drinkCup so that it is accessible in the template (html)

We've still got a few more pieces of logic to move over to the setup() hook. Lets take a look at how it will look once it's fully migrated

<template>
  <div id="app">
    <h2>{{date}}</h2>
    <p>I've drank {{cupsOfWater}} cups of water today 🥤</p>
    <button @click="drinkCup">I drank a cup</button>
    <p v-if='cupsOfWater > 0'>I drank the last cup at {{lastCup}}</p>
  </div>
</template>

<script>
import {ref, onMounted, watch} from 'vue'
export default {
  setup(){
    const cupsOfWater = ref(0)
    function drinkCup(){
      cupsOfWater.value++
    }

    const lastCup = ref('')
    watch(cupsOfWater, ()=>{
      lastCup.value = new Date().toTimeString()
    })

    let date = ref('')
    onMounted(()=>{
      date.value = new Date().toDateString()
    })

    return {
      date,
      cupsOfWater,
      drinkCup,
      lastCup
    }

  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

Composition Codepen

The logic in the above codeblock is clearly separated into functional blocks. We immediately can tell which variables belong to which piece of functionality.

Give it a try in your own projects! Vue2 now has a plugin composition-api that you can install. This will give you a good idea of how your future migration will go and might make it easier for you to adapt when the time comes to fully migrate.

The Goal

With this article I wanted to provide another side by side example of Options to Composition API migration. When I was looking through the documentation I didn't find enough of these. Let me know if you want me to create more!

Check out HTML All The Things

HTML All The Things is a web development podcast and discord community which was started by Matt and Mike, developers based in Ontario, Canada.

The podcast speaks to web development topics as well as running a small business, self employment and time management. You can join them for both their successes and their struggles as they try to manage expanding their Web Development business without stretching themselves too thin.

Our latest episode takes the bold stance that Vue is Better Than React

Top comments (5)

Collapse
 
dgloriaweb profile image
dgloriaweb • Edited

Hi, thanks for the article, just what I've been looking for. So if I have an api request in a method, then I define the result variables, and then in a function call the api?

export default {
  setup() {
    const content = null;
    function fetchData() {
      jobService.getMyJobs()
        .then((response) => { this.content = response; }
        .catch((error) => {
          console.log(error);
        });
    }
    return {
      content,
     fetchData
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mikehtmlallthethings profile image
Mikhail Karan

I don't think you need this.content = response

Just content = response

Collapse
 
dgloriaweb profile image
dgloriaweb

Hi, content (without this) doesn't pick up the value of response. Do you know why? Thanks.

Thread Thread
 
dgloriaweb profile image
dgloriaweb

Ignore me, need to add . value...
content.value = response.data. ...

Thread Thread
 
mikehtmlallthethings profile image
Mikhail Karan

yeah sorry! I forgot, haven't used vue3 in a couple months.

Totally right though. .value to get the value. Thanks for updating!