From my point of Vue: Composition API
Tags: javascript, vue, webdev, programming
Published: 2021-10-07 14:33:23

With the new version, Vue has become more powerful, with things like performance improvements, reduced bundle size, better typescript support, Composition API, and much more. 

Here we are going to explore the last one, the Composition API. I have played with it to build some of my latest projects and I would like to share from that experience **4 reasons why you should consider having this in your toolbox**.

## What is the Composition API?

The composition API is an alternative to the traditional way of writing Vue components. instead of having to export a Vue object with different properties.

```js
export default {
  name: 'MyComponent',
  components: { ... },
  props: { ... },
  data() { return { ... } },
  computed: {},
  mounted() { ... }
  methods: {}
}
```

Now Vue has decoupled its API in standalone functions that allows us to manage reactivity, control lifecycle. It would look like:

> Notice: at the time of writing this post Vue 3.2.6 is the latest version and `<script setup>` is no longer an experimental feature and in fact, is the [recommended way](https://github.com/vuejs/rfcs/discussions/378#discussioncomment-1197332) to go, so in the code examples written here, we are going to use this style.

```js
<script setup>
import { ref, reactive, computed } from 'vue';

// Every defined variable is exposed to the template
const salute = ref('Hello world');
const persona = reactive({
  name: 'Jesus Guerrero'
  age: 25,
});
const greeting = computed(() => {
   return `${salute.value}, I am ${persona.name} and have ${persona.age} years old`.
});

// Every function is available in template
const sumAge = () => {
  persona.age ++;
}
</script>
```

Let me explain a little bit what we are doing here. First, we are importing **ref** and **reactive** which are the principal ways of adding reactivity to our variables. **ref **is for primitive types like `Number`, `String`. but in order to make them reactive, Vue has to wrap it in an `Object` that's why we have to use `salute.value` to access its real value.

**Reactive** on the other hand is for non-primitive values like `Objects` and `Arrays` and we don't need to use `.value` to manage them and the result is deep reactive.

The other function we imported from Vue was **computed** that does the exact same thing as Vue 2 but now is a function that accepts a callback. Its value is going to change whenever one of its reactive dependencies changes.

That looks pretty different from what we had before. doesn't it?

I want to stop at this point to explain something that you might be wondering, why this was needed and what is the real value it brings to the Vue ecosystem.

## Why the Composition API was needed

There has been a lot of claims about the complexity added with Composition API but it's nothing to fear. First, because the options API is right there, is valid and is going to coexist with the composition API (but is better if you do the change), and second, once you get used to it and understand its use cases you'll never look back.

I got two main reasons: 

Vue worked very well for middle and large projects even though was a claim that other frameworks were better to handle the complexity of large projects but let's be honest, large projects are complex themselves. with that said Vue could do a better job covering some edge cases like:

- Introduce better support to Typescript.
- Provide a better way to share functionality across different components and across the app (a more explicit way than **Mixins** at least).

Vue core team shared the [reasons](https://v3.vuejs.org/guide/composition-api-introduction.html#why-composition-api) of the changes in a section you can read if you have not read yet. They put a magnific work and in my personal case, I think that they brought solutions to all that and went beyond.

## Benefits of the Composition API

I'd like to share some benefits you're given by having Composition API in your toolbox: 

### 1- Order code by Domain.

With the Options API where we ordered our code not by logical concerns and behavior

```js
export default {
  name: 'MyComponent',
  components: { ... },
  props: { ... },
  data() { return { ... } },
  computed: {},
  mounted() { ... }
  methods: {}
}
```

Let's add another responsibility to our previous example, and add a list of Interest that the end-user can filter.

```vue
<script setup>
import { ref, reactive, computed } from 'vue';

// presentation
const salute = ref('Hello world');
const persona = reactive({
  name: 'Jesus Guerrero'
  age: 25,
});
const greeting = computed(() => {
   return `${salute.value}, I am ${persona.name} and have ${persona.age} years old`.
});


// interests
const interest = reactive({
  searchText: "",
  list: ['javascript', 'hashnode', 'vue', 'vue3', 'laravel', 'supabase', 'productivity'],
});

const executeSearch = (searchText, list) => {
  let filteredList = list
  if (searchText) {
    filteredList = list.filter((item) =>
      item.includes(searchText.toLowerCase())
    );
  }
  return filteredList;
};

const filteredInterest = computed(() => {
  return executeSearch(interest.searchText, interest.list);
});
</script>

```

We used a computed, another reactive object but is grouped by domain, by logical concern. It's clear for us to understand that the first part of the code is related to the presentation and the second one to the interests list.

### 2 - Elegant support to typescript.

It's impossible to deny the huge benefits typescript brings to the JS community, managing large codebases with different people is better with types, static checks and help offered by the code editors makes everybody's lives easier.

The typescript support in Vue 3 is neat, simple and elegant:

```ts
<script lang="ts" setup >
import { ref, reactive, computed } from 'vue';

...
// interests
const interest = reactive({
  searchText: "",
  list: ['javascript', 'hashnode', 'vue', 'vue3', 'laravel', 'supabase', 'productivity'],
});

const executeSearch = (searchText: string, list: string[]): string[] => {
  let filteredList = list
  if (searchText) {
    filteredList = list.filter((item) =>
      item.includes(searchText.toLowerCase())
    );
  }
  return filteredList;
};

const filteredInterest = computed(() => {
  return executeSearch(interest.searchText, interest.list);
});
</script>

```

### 3 - Composables.

As we now have the reactivity exposed we can extract functionality to its own space and reuse them where we want.

Let's extract the search functionality into its own **composable** and let's use typescript to add types.

```ts
// useSearch.ts
import { computed, Ref } from "vue"

export const useSearch = (searchText: Ref<string>, list: Ref<string[]>) => {
    const executeSearch = (searchText: string, list: string[]): string[] => {
        let filteredList: string[] = list
        if (searchText) {
          filteredList = list.filter((item) =>
            item.includes(searchText.toLowerCase())
          );
        }

        return filteredList;
    };
      
    const filteredList = computed(() => {
        return executeSearch(searchText.value, list.value);
    });

    return {
        filteredList
    }
} 
```

Notice how we declare a function that takes two **refs** `searchText` and `list` we need to pass **ref** here and not plain `string` and `array` because we need reactivity
to return a filtered list that will change whenever we search or add another item to the list.

To use this in our components just import and call the composable like this:

```vue
<script setup lang="ts">
import { reactive, toRefs } from "vue";
import { useSearch } from "../../utils/useSearch";

const interest = reactive({
  searchText: "",
  list: ['javascript', 'hashnode', 'vue', 'vue3', 'laravel', 'supabase', 'productivity'],
});

const { searchText, list } = toRefs(interest);
const { filteredList: filteredInterest } = useSearch(searchText, list);
</script>
```

Notice how we use our composable like a normal function, and we imported a new function from Vue here `toRefs` we cant destructure a `reactive` object like a normal javascript object without losing reactivity instead we need to transform from reactive to `ref` as our composable accepts a `ref`s as arguments  and that's exactly what **toRefs** does.

The code here is extremely readable and explicit. We just reduced our component size in lines, extracted a functionality that can be used in other components with different UI's and items but the same needs, and we are going to understand faster what's happening if we let the codebase for three or six months and need to change something (hopefully).

> This is maybe the more powerful use case that the Composition API solves important libraries offer composable functions like [vueuse](https://vueuse.org/), [useMotion](https://motion.vueuse.org/) and others that have made it easier to work with APIS like local storage, animation, and sensors.

### 4 - Exposed magic.

The last one is personal, I like the fact that it feels natural to share reactive functionality in vue in a more explicit way than **mixins**; I don't need to read to know where a function comes from if I am using two mixins in a component

## Wrapping up

I am not a pythonist but I think that its [zen manifest](https://www.python.org/dev/peps/pep-0020/) does a great job describing the philosophy of coding, the lines I like the most are: 

>Explicit is better than implicit.

>Simple is better than complex.

>Complex is better than complicated.

The composition API is a good example of this philosophy, is Vue exposing its powers and giving them to us to build more powerful and scalable apps,  improve the developer experience and make the code more portable across the app, and why not, between projects.

That's all for today, In the next post we'll focus a little more on `refs` and `reactive` as we understand better what is and the benefits of the new API.

Thanks for reading, as always the comments and my [Twitter](https://twitter.com/JesusntGuerrero) are open to any question about the topic and have a nice day.

## Resources
- [Repo with this examples](https://github.com/jesusantguerrero/point-of-vue/tree/master/src/views/composition)
- [Introduction to composition API](https://v3.vuejs.org/guide/composition-api-introduction.html)
- [vueuse](https://vueuse.org/functions.html)