This post is an exploration into Vue.js' new composition API, which brings more scalability and readability into the framework we already know and love.

If you're unfamiliar with Vue.js - It's a framework for building small to large front-end web development projects. The core premise of Vue.js is that it is incrementally adoptable. It also ships with a CLI tool that helps you hit the ground running.

Now, if you haven't used Vue before, the new composition API may not be that interesting to you. For the crowd who has become a Vue professional - here's what you need to know.

How to get started with the API

To use the new composition API you simply need to plug it into an existing Vue application, to create one simply run:

npx @vue/cli create vue-composition-app

Then install the composition API plugin:

yarn add @vue/composition-api

Finally, you'll have to use it in your app:

src/main.js
import Vue from 'vue'
import App from './App.vue'
import CompositionApi from '@vue/composition-api'

Vue.config.productionTip = false
Vue.use(CompositionApi)

new Vue({
  render: h => h(App),
}).$mount('#app')

And that's all that you'll need to start using the API. Next up, let's look at the following features brought by the API:

  • setup function
  • reactive properties
  • computed properties
  • methods
  • props and the emit event

The setup function

In Vue 2.x every component has an exported object. The properties in this object is known as the options.

<template>
  <h1>{{ message }}</h1>    
</template>

<script>
export default {
  data() {
    return {
       message: 'Hello World!'
    }
  },
  computed: {
    someProperty() {
      return "value"
    }
  },
  methods: {
  	...
  }
}
</script>

The example above depicts a small component with data, methods and computed properties. In this example we can access our message data property directly by name in the template and in our methods by this.message

With the new composition API we can do away with these options and replace it with one setup function.

<template>
  <h1>{{ message }}</h1>    
</template>

<script>
export default {
  setup() {
  	// How do we make message available??
  }
}
</script>

But how do we access a message property? Through reactive():

<template>
  <h1>{{ state.message }}</h1>    
</template>

<script>
import { reactive } from '@vue/composition-api'

export default {
  setup() {
    const state = reactive({
      message: 'Hello World!'
    })
    
    return {
      state
    }
  }
}
</script>

Notice how state is simply a variable, the reactive function allows Vue to know that it should update the render when this property changes.

Computed properties can also be used to create a new reactive property based on the value of another:

...

<script>
import { reactive, computed } from '@vue/composition-api'

export default {
  setup() {
    const state = reactive({
      message: 'Hello World!'
    })
    
    const messageForJohn = computed(() => 
      state.message.replace('World', 'John'))
    
    return {
      state,
      messageForJohn
    }
  }
}
</script>

The computed property messageForJohn now will print 'Hello John!'.

The new composition API also has ways of adding methods to the instance. In these methods we can directly access the reactive properties, instead of having to say this.message we can simply say state.message.

export default {
  setup() {
    const state = reactive({
      message: 'Hello World!'
    })
    
    const messageForJohn = computed(() => 
      state.message.replace('World!', 'John!')
    
    function updateGreeting(newGreeting = 'Hi') {
       state.message = state.message.replace('Hello', newGreeting)
    }
      
    return {
      state,
      messageForJohn,
      updateGreeting
    }
  }
}
</script>
Along with reactive, there is another function called 'ref' which is similar - read more about it here.

We'll access methods the same way we usually do, for example:

<template>
    <button @click="updateGreeting">Update</button>
</template>

The setup function accepts two arguments: props and context. The props parameter is the props that the component receives - since we can't do this.propItem.

The context has the following properties:

  • attrs
  • slots
  • parent
  • root
  • emit

Check out the Vue.js docs for more information about the above - they're not new - but simply accessible without 'this'. Check out this example to-do application to see the usage in action.

Why is the team taking this approach?

A lot of you may wonder why the team would want to re-write the way we use the framework; and some of you are probably worried that the way we do it now may be destroyed in Vue 3.x. Luckily the team will give you a choice to use it or not, so you can always continue using it as you always have.

As for the 'why' - there is a lot of good reason for the new API. Look at this example posted by the maintainers:

Options API vs. Composition API

The coloring in these images are sections in a very large Vue.js component that have the same concern. By 'same concern' I simply mean that the logic revolves around the same outcome.

With the options API, reading a component with many different applications was very difficult. It was grouped on a option level (data, methods etc.) instead of a logical level.

With the composition API we aren't required to group our logic like this; we can separate our logic on a function-level, eg:

...
<script>
  import { reactive, onMount } from "@vue/composition-api"
    
  export default {
    setup() {
      const { username } = useUserModule()
        
      const {
       authenticated,
       adminRole
      } = useCheckAuthentication(username)
        
      return {
        username,
        authenticated,
        adminRole
      }
    }   
  }
    
  // We move our concerns out of the object, 
  // this can even be imported
  function useUserModule() {
    const username = ref('')
    
    onMount(() => {
      username.value = localStorage.getItem('user')
    })
      
    return { username }
  }
  
  // Separating auth from userState
  function useCheckAuthentication(user) {
    const { authenticated } = ref(false)
    const { adminRole } = ref(false)
    
    onMount(() => {
      // Some pseudo code
      if(db.user(user)) {
        authenticated.value = true
        
      }
      
      if(db.user(user).role === 'admin') {
        adminRole.value = true
      }
        
      return {
        authenticated,
        adminRole
      }
    })
  }
</script>

The code above is hypothetical, but it showcases the importance of logical separation. We don't have to figure out which data properties or methods belong to which area of the component, we can simply group the logic in readable, reusable functions.

I hope that this intro to the Vue composition API was useful. I'm excited to see the updates as work on Vue 3.x progresses. Tweet at me (@eckhardtdreyer) with your thoughts and ideas. If you want to watch a to-do application built with the new composition API subscribe to Kaizen Codes Youtube Channel.