Composition API will be a core feature of Vue 3, with many changes and performance improvements. It is available in Vue 2 through the NPM plugin @vue/composition-api. This article will take you to understand:

  1. @vue/composition-apiCommon API usage
  2. Vue3 code logic extraction and reuse
  3. How to useprovide+injectalternativevuexplan

Vue2 use composition – API

Add main file main.ts or app.vue

import Vue from 'vue'

import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)

Copy the code

Composition API no longer passes in data, Mounted and other parameters, but realizes bidirectional data binding and life cycle function execution through ref, onMounted and other methods introduced.

The core of grammar

Reactive: A reactive proxy that receives a common object and returns that common object.

Ref: Accepts a parameter value and returns a responsive and mutable ref object. The ref object has a single.value attribute that points to an internal value.

Computed: Pass in a getter function that returns a ref object that cannot be manually modified by default.

Readonly: Passes in an object (reactive or plain) or ref and returns a read-only proxy for the original object. A read-only proxy is “deep” and any nested properties inside an object are also read-only.

WatchEffect: Executes a function passed in immediately, traces its dependencies in a responsive manner, and rerunts the function when its dependencies change. You can explicitly call the return value to stop listening.

Watch: fully equivalent to 2.x this.\$watch (and the corresponding option in watch).

The setup function

The first API I’ll cover now is the Setup function. The setup function is a new component option. As an entry point for using the Composition API within components. So let’s do a quick demo

<template>

  <button @click="increase">count is: {{ count }}</button>

</template>

<script>

  export default {

    setup() {

      let count = 0

      const increase = (a)= > count++

      return { count, increase }

    },

  }

</script>

Copy the code

1. Call timing

Create the component instance, initialize props, and then call the setup function. From the vue2 lifecycle hook perspective, it is called after the beforeCreate hook and before the Created hook.

2. Used in templates

If Setup returns an object, the properties of the object will be incorporated into the rendering context of the component template.

3. Use in render function/JSX

Setup can also return a function that uses reactive data from the current setup function scope:

import { h, ref, reactive } from '@vue/composition-api'



export default {

  setup() {

    const count = ref(0)

    const object = reactive({ foo'bar' })



    return (a)= > h('div', [count.value, object.foo])

  },

}

Copy the code

4, Two parameters: props(note that the props object is responsive), context(this selectively exposes some properties from 2.x)

const MyComponent = {

  setup(props, context) {

    let {

      attrs,

      emit,

      isServer,

      listeners,

      parent,

      refs,

      root,

      slots,

      ssrContext,

    } = context

  },

}

Copy the code

ref & reactive

In app. vue, click events bind increase and then change count, but the page does not change. This is because the setup function returns an object in which count is not reactive data. At this point, we need to master the responsive system API, which we can create using REF and Reactive.

<template>

  <button @click="increase">

    count is: {{ count }}, state.count is {{ state.count }}

  </button>

</template>



<script>

  import { ref, reactive } from 'vue'

  export default {

    setup() {

      let count = ref(0// { value: 0 }

      let state = reactive({ number0 })

      const increase = (a)= > {

        count.value++

        state.count++

      }

      return { count, state, increase }

    },

  }

</script>

Copy the code

Accepts a parameter value and returns a reactive and mutable REF object. The ref object has a single.value attribute that points to an internal value.

When ref is returned as an attribute of the rendering context (that is, in the object returned by Setup ()) and used in the template, it is automatically unwrapped without the need to write an additional.value inside the template

Vue already has the concept of “ref”. But only to get the DOM element or component instance (” template reference “) in the template. The new REF system is used for both logical state and template references.

Reactive receives a common object and returns a reactive proxy for that common object.

Reactive transformations are “deep” : they affect all nested properties inside the object. The Proxy implementation based on ES2015 does not return a Proxy object equal to the original object. It is recommended to use only proxy objects instead of relying on primitive objects.

Do not deconstruct the returned proxy object, as this will make it unresponsive:

<template>

  <button @click="increase">count is: {{ count }}</button>

</template>



<script>

  import { ref, reactive } from '@vue/composition-api'

  export default {

    setup() {

      let state = reactive({ count0 })

      const increase = (a)= > state.count++

      return { ...state, increase } // Expanding the state property will become unresponsive

    },

  }

</script>

Copy the code

ToRef and toRefs

So what if we really want to expand state and use count instead of state.count in the template? We can use the toRef and toRefs apis to convert toRef objects, which we have already shown can be used directly in templates.

ToRef can be used to create a REF for properties of a Reactive object. This REF can be passed and remains responsive.

<template>

  <button @click="increase">

    count is: {{ count }},count2 is: {{ count2 }}

  </button>

</template>



<script>

  import { ref, reactive, toRef, toRefs } from '@vue/composition-api'

  export default {

    setup() {

      let state = reactive({ count0 })

      let countRef = toRef(state, 'count')

      let state2 = reactive({ count20 })

      const increase = (a)= > state.count++

      let stateAsRefs = toRefs(state2)

      return { count: countRef, increase, ... stateAsRefs }

    },

  }

</script>

Copy the code

Convert a reactive object to a normal object, each property of which is a ref, corresponding to the reactive object property.

computed & watch

const countDouble = computed((a)= > count.value * 2)

watch(

  (a)= > state.count,

  (count, prevCount) => {

    / *... * /

  }

)

Copy the code

Code logic extraction and reuse

The first obvious advantage of the Composition API is that it is easy to extract logic. To solve the

Logic to extract

export const useCount = (number) = > {

  const count = ref(0)

  const increase = (a)= > {

    count.value += 1

  }

  const reset = (a)= > {

    count.value = 0

  }

  onMounted((a)= > {

    count.value = number

  })

  return {

    count,

    increase,

    reset,

  }

}

Copy the code

Code reuse

// Another file uses:

const { count, increase } = useCount(1)

console.log(count) / / output 1

increase()

console.log(count) 2 / / output

reset()

console.log(count) //输出0

Copy the code

Effectively solve the mixins reuse name conflict, it is difficult to identify the name from which mixin file problem.

Replace VUEX state management

A state store can be placed in a single file or directory, such as config, which can be used only by a global component

//context/config.ts

import { provide, inject, ref, onMounted, readonly } from '@vue/composition-api'

const configSymbol: symbol = Symbol()



export const useProvider = {

  setup() {

    let config = ref(null)

    const configServer = async() = > {

      // await some asynchronous operations, such as API, etc

      config.value = { name: 'name' }

    }

    onMounted(async() = > {

      await configServer()

    })

    provide(configSymbol, {

      // Export read-only config. Only functions can change the state internally

      config: readonly(config),

    })

  },

}



export const useInject = (a)= > {

  return inject(configSymbol)

}

Copy the code

Injected on the topmost component (such as main.ts), config can be used in all components

import { defineComponent } from '@vue/composition-api'

import { useProvider } from './context/config'

export default defineComponent({

  setup() {

    useProvider()

  },

})

Copy the code

The business logic page uses Config

import { useInject } from './context/config'

const Components = {

  setup() {

    const { config } = useInject()

    console.log(config.value.name) // Print "name"

    return {

      config,

    }

  },

}

Copy the code