Composition API, also known as composite API, is a new feature of Vue3. X. Before Composition API, vUe-related business codes need to be configured to a specific area of option. This is ok for small and medium-sized projects, but in large projects, it will lead to complex maintenance and low code reusability. The composition-API in Vue3. X was created to solve this problem.

Compositon-api provides the following functions:

Setup Ref Reactive watchEffect Watch Hooks for computed toRefs life cycleCopy the code

Setup () function

Is a new attribute in VUE3 that is specifically provided for components. It provides a unified entry point for using vue3’s new Composition API features.

Setup () function execution timing

The setup function is executed after beforeCreate and before created, that is, before the component is created. Because the component instance has not been created when setup is executed, there is no this in the Setup option. This means that you will not be able to access any properties declared in the component — local state, computed properties, or methods — except props.

2. Arguments in the setup() function

The first argument to the setup() function is props. The props data received by the component can be accessed within the setup() function. The props in the setup function is reactive and will be updated when a new prop is passed in.

props: {
  title: String
}
setup(props) {
    console.log(props.title)
}
Copy the code

Because props are reactive, you can’t use ES6 deconstruction because it eliminates the responsiveness of prop. If you need to deconstruct a prop, you can do so safely by using toRefs in the Setup function.

Import {toRefs} from 'vue' setup(props) {const {title} = toRefs(props) console.log(title.value)}Copy the code

The second argument to setup() is context, which is a context object through which the instance of Vue, this, can be accessed.

setup(props, context) {
    context.attrs
    context.slots
    context.parent
    context.root
    context.emit
    context.refs
  }
Copy the code

2. Ref () function

Creates a reactive data object based on the given value. The return value is an object containing only a. Value attribute. Ref is used to define reactive strings, numbers, arrays, and Bool types

<template>
  {{title}}
</template>

<script lang="ts">
import { ref } from 'vue';

export default {
  name:'App',
  setup(){
    const title=ref("hello world");
    return{
      title,
    }
  }
}
Copy the code

If you want to change the value in ref, you need to change the value property

Const count = ref(0) const count = ref(0) Console.log (count.value) // prints 0 // makes the value of count +1 count.value++ // prints count again Console. log(count.value) // Prints 1Copy the code

Note: The new ref overwrites the old ref, as shown in the following code:

Const c1 = ref(0) const state = reactive({c1}) // replace old ref c1 with new ref c2 state.c1 = c2 state.c1++ console.log(state.c1) // print 10 Console. log(c2.value) // prints 10 console.log(c1.value) // prints 0Copy the code

In the setup() function, the reactive data created by ref() returns an object, so it needs to be accessed with.value; Outside of the setup() function, you don’t need the.value. You can access it directly from the template.

Reactive (

Take a normal object and return a responsive object. In vue2.x, we only need to define a data in data() to make it reactive, whereas in Vue3.0, reactive data is created using reactive functions such as reactive or ref

<template> {{userInfo.username}}----{{userInfo.age}} </template> <script lang="ts"> import { reactive } from 'vue'; Export default {name:'App', setup(){const userInfo=reactive({username:" zhang ", age:18}) return{userInfo,}}}Copy the code

ToRefs deconstructs responsive object data

Converts a reactive object to a normal object, and every attribute node on that normal object is reactive data of type REF () because userInfo is used for each call. Return userInfo = userInfo = userInfo = userInfo = userInfo; UserInfo, but the first time the data can be displayed, the data is not responsive, the page data does not update when the data changes, so vue3 can use toRefs to solve this problem

<template> {{username}}----{{age}} </template> <script lang="ts"> import { toRefs,reactive } from 'vue'; Export default {name:'App', setup(){const userInfo=reactive({username:" zhang ", age:18}) return{... toRefs(userInfo), } } }Copy the code

5. Computed () Attributes

Used to create a calculated property and the return value is an instance of ref().

Const count = ref(1) const count = ref(1) Create a responsive computed property, plusOne, that automatically computes based on the dependent ref and returns a new ref const plusOne = computed(() => count.value + 1) Console. log(plusone. value) // Outputs 2 plusone. value++ // errorCopy the code

Readonly () readonly

Passing in an object (reactive or plain) or ref returns a read-only proxy of the original object. A read-only proxy is “deep” and any nested properties inside an object are also read-only. Passing in a normal object returns a read-only proxy. Passing ordinary values or strings cannot become read-only, such as readonly(‘ ABC ‘)

import { reactive, readonly } from "vue"; export default { name: "Readonly", setup() { const original = reactive({ count: 0 }); const copy = readonly(original); setInterval(() => { original.count++; copy.count++; Set operation on key "count" failed: target is readonly. Proxy {count: 1}}, 1000); return { original, copy }; }};Copy the code

7. Watch listener

Lazy is not executed when the page is displayed for the first time. It is executed only when the data changes. The current and original values of parameters are retrieved

<template>
  <input type="text" v-model="name">
</template>

<script lang="ts">
import { ref,watch } from 'vue';
export default {
  name:'App',
  setup(){
    const name = ref('leilei')
    watch(name, (curVal, prevVal) => {
        console.log(curVal, prevVal)
    })
    return{
      name,
    }
  }
}
Copy the code

Listen for reference types —–

<template> Name: <input v-model="name" /> englishName: <input v-model="englishName" /> </template> <script lang="ts"> import { reactive,watch,toRefs } from 'vue'; setup() { const nameObj = reactive({name: 'leilei', age: Watch (() => nameobj.name, (curVal, prevVal) => {console.log(curVal, prevVal) => {console.log(curVal, prevVal) PrevVal)} watch([() => nameobj.name, () => nameobj.age], ([curName, curEng], [prevName, curEng]) => { console.log(curName, curEng, '----', prevName, curEng) setTimeout(() => { stop() }, 5000) }) const { name, englishName } = toRefs(nameObj) }Copy the code

Watch can also be made non-lazy and executed immediately by adding the third parameter, immediate: true

watch([() => nameObj.name, () => nameObj.name], ([curName, curEng], [prevName, curEng]) => {
    console.log(curName, curEng, '----', prevName, curEng)
    setTimeout(() => {
        stop()
    }, 5000)
}, {
    immediate: true
})
Copy the code

WatchEffect listener

There is only one callback function without too many arguments. 1. Execute immediately, no laziness, the first load of the page will execute. 2, automatic detection of internal code, the code in a dependent will perform 3, do not need to pass to listen for content automatically perceive code depends on, do not need to pass many parameters, as long as the delivery before 4, inability to obtain a callback function data can only get the current value of 5, some = asynchronous operations here will be more appropriate

const stop = watchEffect(() => {
    console.log(nameObj.name) 
    setTimeout(() => {
        stop()
    }, 5000)
})

Copy the code

Differences between Watch and watchEffect:

Watch can access values before and after data changes. The data that a watch listens to a single data source can be a reactive data created by reactive (a getter function that returns a value) or a REF

Provider Inject component value transfer

Typically, we use props when we need to pass data from a parent component to a child component. Imagine a structure like this: you have some deeply nested components, and you only need something from the parent of the deeply nested child component. In this case, you still need to pass prop through the entire component chain, which can be annoying. In this case, we can use provide and Inject to make the parent component a dependency provider for all its children, no matter how deep the component hierarchy is. This feature has two parts: the parent component has a provide option to provide data, and the child component has an Inject option to start using this data.

Non-combinatorial APIS:

<! -- SRC /components/ mymap.vue --> <template> <MyMarker /> </template> <script> import MyMarker from '. Export default {components: {MyMarker}, provide: {location: 'North Pole', geolocation: {longitude: 90, latitude: 135 } } } </script> <! -- the SRC/components/MyMarker. Vue -- > < script > export default {inject: [' location ', 'geolocation']} < / script >Copy the code

In the combinatorial API:

Provider: When using provide in setup(), we first import the provide method explicitly from vue. This allows us to define each property by calling the provide time.

The provide function allows you to define a property with two arguments:

Using the MyMap component, we provide values that can be refactored as follows:

<! -- SRC /components/ mymap. vue --> <template> <MyMarker /> </template> <script> import {provide} from 'vue' import MyMarker from './MyMarker. Vue export default {components: {MyMarker}, setup() {provide(' location ', 'North Pole') provide(' geolocation ', {longitude: 90, latitude: 135 }) } } </script>Copy the code

Inject: When you use Inject in setup(), you also need to import it explicitly from vue. Once we do that, we can call it to define how to expose it to our component.

The Inject function takes two parameters:

The name of the property to be injected a default value (optional) Using the MyMarker component, it can be refactored using the following code:

<! -- the SRC/components/MyMarker. Vue -- > < script > import {inject} from 'vue' export default {the setup () {const userLocation = Inject (' location ', 'The Universe') const userGeolocation = inject(' geolocation ') return {userLocation, userGeolocation } } } </script>Copy the code

Provider Inject responsiveness

The parent component:

import { provide, ref, Reactive} from 'vue' setup() {const location = ref(' Beijing ') const geolocation = reactive({longitude: 90, latitude: 135}) const updateLocation = () => {location.value = 'Shanghai'} provide(' location ', location); Dojo.provide (" geolocation ", geolocation); Return {updateLocation}} < button@click ="updateLocation"> Change location</button>Copy the code

Child components:

Import {inject} from 'vue' export default {setup() {const userLocation = inject(' location ', 'The Universe') const userGeolocation = inject(' geolocation ') return {userLocation, userGeolocation}}} </script>Copy the code