Migrating components from Option API to Composition API on Vue 🛠️
Tags: vue, javascript, webdev, tutorial
Published: 2023-02-19 20:45:08

Today I will show you how to migrate your components from the "old" Option API to the new Composition API on Vue 3.

### First of all, what is the composition api?
Good question! The official documentation says

> Composition API is a set of APIs that allows us to author Vue components using imported functions instead of declaring options.
Composition API is a built-in feature of Vue 3 and Vue 2.7. For older Vue 2 versions, use the officially maintained @vue/composition-api plugin. In Vue 3, it is also primarily used together with the `<script setup>` syntax in Single-File Components.


### Okay, great, but why should I use the Composition API?
The primary benefit of the Composition API is that it enables clean, efficient logic reuse in the form of composable functions. It solves all the drawbacks of mixins, the primary logic reuse mechanism for the Options API.
Also, it has more adeventajes like:

- More Flexible Code Organization.
- Better Type Inference.
- Smaller Production Bundle and Less Overhead.
- Better use with Typescript.


### Okay, so how are we going to do this?
I prepared this Vuejs component and we will migrate it piece by piece.
{% embed https://gist.github.com/nicolasmontielf/edd85318c20650b26baf5b140388aaac %}

**1. Components**.
With the Composition API, you don't need to declare the components you want to use, just import them and they will be available in your template.

**2. Props**.
You can define the props in much the same way as before. You need to declare a variable (usually called props) and use the [defineProps] (https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits) method. This method is automatically available inside the `script setup` tag.

```javascript
const props = defineProps({
    userId: {
        type: String,
        required: true,
    },
    cartId: {
        type: String,
        required: true       
    },
})
```

**3. Event emitters**.
As with props, you need to define a constant and use a method available within the `script setup` tag. This is called [defineEmits](https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits).

```javascript
const emit = defineEmits(['checkout'])
```

**4. Data**
With the data, we can now see much cleaner and more readable javascript. For the data on your component, you have two cases: data with reactivity, or a simple constant.

For the data with reactivity, you need to import `ref` and put the initial value of the variable inside the method.

```javascript
import { ref } from 'vue'

const items = ref([]) // This is the initial value, we are going to fill it later.
```

And for the constant variable, as easy as javascript.

```javascript
const maybeAConstantObject = {
    someKey: 'someValue',
    anotherKey: 'anotherValue'
}
```

**5. Methods**.
Methods, like variables, are now just simple javascript functions, lets show some examples:

```javascript
 function addItem(item) {
    items.value.push(item);
}

function proceedToCheckout() {
    // Here you can also see how emit an event.
    emit('checkout', items.value);
}
```

**6. Computed properties**
Okay, this is a bit more tricky, but still not complicated. To do this, we need to import the `computed` method and inside it, we put a callback that returns the value of the property.

```javascript
import { computed } from 'vue'

// So now this variable will return the sum of all the items in the cart, and it will be executed everytime the `items` change.
const total = computed(() => {
    return items.value.reduce((total, item) => {
        return total + (item.price * item.quantity)
    }, 0)
})
```

**7. Watchers**
As in some previous cases, you need to import the `watch` method from Vue, and this takes two arguments; the first is the data you are watching (this should be reactive data, like `items` in this case), and the second argument is a callback that is invoked when the data changes.

```javascript
import { watch } from 'vue'

// The console.log will be executed every time items changes.
watch(items, () => {
    console.log('Cart items changed')
})
```

**8. Created**
So we don't have a specific onCreated here, we just need to create the function and initialise it inside the `script setup`. Also, I leave here the list of [Lifecycles of a Vue component](https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram) as a reference. Remember, here **the DOM doesn't exist yet.**

```javascript
<script setup>
    // This will be executed when the component is created.
    console.log('Cart created')
</script>
```

**9. On Mount**
This is a lifecycle that exists in the API, so we need to import it from vue. Inside it takes a callback that is executed after the component is mounted. Here you already have access to the DOM.

```javascript
// This call to the endpoint will run when the component is mounted.
onMounted(() => {
    fetch('/api/cart/' + props.cartId)
        .then(response => response.json())
        .then(items => items.value = items)
        .catch(error => console.error(error));
})
```

**This is the final result:**
{% embed https://gist.github.com/nicolasmontielf/49b80af5b78d0801069b746f7d57d858 %}


### To summarize
Migrating from the Option API to the Composition API is not something complicated, from my own experience, after a few components, it will be an easy task for you.
Now the question, should you do it? It's up to you, it's not necessary and if you prefer the Option API, you won't have any problem with it in the near future.

If you have any recommendation or some case is missing, let me know and I can add it :)

That's all, I hope it can be helpful for you 🥳