Vue 3.0 introduced a new way of writing code, called Composition API, which is a functional API different from Vue 2.0 Options API. Instead of defining components by specifying a long list of options, the Composition API allows users to compose logic and code as freely as they write functions. So let’s see what the Composition API is.

What is the Composition API?

Composite apis: A set of less intrusive, functional apis that allow us to “compose” a component’s logic more flexibly

Let’s look at a simple example

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
  import { reactive, computed } from 'vue'

  export default {
    setup() {
      const state = reactive({
        count: 0.double: computed((a)= > state.count * 2})),function increment() {
        state.count++
      }

      return {
        state,
        increment,
      }
    },
  }
</script>
Copy the code

So let’s take a look at what’s going on with this code, right?

import { reactive, computed } from 'vue'
Copy the code

The Component API presents Component properties in the form of functions, so the first step is to import the required functions. In our example, we use Reactive to create the response properties and computed to create the compute properties.

export default {
  setup() {
    // ...
    return {
      state,
      increment,
    }
  }
Copy the code

There is also a setup function, which is a new component option. As an entry point for using the Composition API within a component, if Setup returns an object, the properties of the object are incorporated into the rendering context of the component template, and the corresponding properties and methods can be used within the template.

Why the Composition API

In Vue2 we use the Options API to write this example

<template>
  <button @click="increment">
    Count is: {{ count }}, double is: {{ double }}
  </button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },

  computed: {
    double() {
      return this.count * 2; }},methods: {
    increment() {
      this.count++; }}};</script>
Copy the code

If we want to reuse this logic in Vue2, we can do so through patterns such as mixins, higher-order components, or non-rendering components (implemented through scope slots).

First, let’s look at the way mixins work

import CounterMixin from './mixins/counter'

export default {
  mixins: [CounterMixin]
}
Copy the code

Here’s the problem with mixins

  • The source of the property exposed in the render context is not clear. For example, when reading a template that uses multiple mixins, it is difficult to see which mixin a property was injected from.

  • Namespace conflict. Mixins may have conflicting properties and methods.

So let’s look at the way the scoped slot works:

<template>
  <Counter v-slot="{ count, increment }">
     {{ count }}
    <button @click="increment">Increment</button> 
  </Counter> 
</template>
Copy the code

With Scoped slots, we know exactly what attributes we can access with the V-slot attribute, which makes it easier to understand the code. The downside of this approach is that we can only access it in the template and only use it in the Counter component scope.

In addition, higher-order and unrendered components require additional stateful component instances, resulting in a performance penalty.

Ok, it’s time for Composition API

function useCounter() {
  const state = reactive({
    count: 0.double: computed((a)= > state.count * 2)});function increment () { count.value++ }

  return {
    state,
    incrememt
  }
}

export default {
  setup () {
    const { state, increment } = useCounter()
    return {
      state,
      increment
    }
  }
}
Copy the code

It’s more elegant, isn’t it? By comparison:

  • The source of the properties exposed to the template is clear because they are values returned by the composed logic function.
  • There are no namespace conflicts and you can name them arbitrarily by deconstruction
  • You no longer need to create component instances just for logical reuse
  • Rely only on its arguments and the Vue global export API, not its subtle This context

In addition to making it easy to extract and reuse logic, Composition apis actually give us a new way of thinking about how to write code.

When trying to understand a component, we are more concerned with “what the component is doing” (the intent behind the code) than “what options the component uses.” Option-based apis write code that naturally expresses the latter, but does not express the former well.

The forced separation of the Options API Options creates a barrier to the logical concerns behind the presentation. Furthermore, when working with a single logical concern, we must constantly “jump” between blocks of option code to find the part that is relevant to that concern.

In the example above, based on the Options API, we have to jump between data, computed, and methods to complete the logic. By means of Composition API, we juxtapose the code of the same logical concern to form an independent logical function.

There is a problem

Of course, there are drawbacks to the introduction of the Composition API.

The composite API provides more flexibility in code organization, but it also requires more developer self-restraint to “get it right,” which allows inexperienced people to write bar code.

In the Options API, there is actually a mandatory convention:

  • Props to set the receive parameters
  • Set variables in data
  • Set the computing properties in computed
  • Set the listening properties in watch
  • Set event methods in methods

You’ll notice that the Options API dictates where we should do what, which forces us to split code to a certain extent. Now with the Composition API, this is no longer the convention, so the code organization is very flexible, and if you are a beginner or a non-thinking coder, the setup code will get more and more complex as the logic gets more and more complex, and the returns inside the setup will get more and more complex. Will fall into the mediation of the “noodle code”.

What we expect is that the setup() function now simply serves as an entry point to call all the composite functions

export default {
  setup() {
    // Network status
    const { networkState } = useNetworkState()

    // Folder status
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({
      networkState,
      currentFolderData,
    })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(
      currentFolderData
    )
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)

    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()

    // Utility tools
    const { slicePath } = usePathUtils()

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath,
    }
  },
}
Copy the code

In Vue 3.0, the Composition API is not the default solution, but the Options API of Vue 2.X will be used. The Composition API will be considered as an advanced feature. Because it’s designed to solve problems that occur primarily in large applications.

References:

  • Vue composite API

Welcome to follow the wechat official account