Why use composition-API
Why, many may ask, should you use composition-API on VUe2? Couldn’t we just upgrade the project to VUE3?
- Ecological issues, many open source libraries are currently being upgraded to VUE3
- If the project is huge, do it
vue2
->vue3
Migration is still very cumbersome. - in
vue2
usecomposition-api
Existing functionality will not be affected and will not be upgraded in the futurevue3
So all you need to do is take the incoming package from@vue/composition-api
Instead ofvue
It is ok
Install @ vue/composition – API
@vue/composition-api
npm install @vue/composition-api
# or
yarn add @vue/composition-api
Copy the code
We need to register it as a plugin. Vue.use()
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
Copy the code
Then you can use some of the vue3 functionality by introducing it into the. Vue component
// use the APIs
import { ref, reactive } from '@vue/composition-api'
//
When you migrated to Vue 3, just replacing '@vue/ comcomposition - API' to 'Vue' and your code should just work.
import { ref, reactive } from 'vue'
Copy the code
TypeScript support
The Vue2 project I’m using now introduces vue-property-decorators and vue-class-Component to support Typescript writing. If I change to composition-API then I’ll just have to write Javascript again. You’ve worked hard to learn TypeScript for nothing.
Vue prior to Vue 2.6 uses flow for type checking, but Vue3 and Vue2.7 released in Q3 use TypeScript for type checking. All composition-apis also support TypeScript
However, TypeScript version >3.5.1 is required
import { defineComponent } from '@vue/composition-api'
// Just write the code in defineComponent and ts static checking will work
export default defineComponent({
// type inference enabled
props: {}setup(props,ctx){}
data(){}
created(){}
mounted(){}})Copy the code
Browser support
Like Vue3, Composition-API supports all modern browsers as well as IE11+, if you want to support lower versions of IE you should install WeakMap polyfill such as Core-js
composition-api VS options api
The following code is the Options API for Vue2. When we reach a certain amount of code, this structure becomes difficult to maintain. At this point, people say, we can use mixins to extract the common logic.
<scirpt>
export default {
components: {}mixins:[xxxMixin]
props: {}data(){
return{
// some reactive data}}created(){
this.getList()
}
methods: {getList(){}
}
}
</scirpt>
Copy the code
But I think a lot of people have this problem: I can’t find a method or variable in
or methods until I see a mixins option in script. Then, if there are multiple mixins in the mixins, you have to go to each file to find the corresponding variable
In addition to the above, if we need to add new functionality to the.vue file, we will most likely need to do the following steps
1 one ️ Define the corresponding variable in the data option so that this variable can be made responsive
2 discount ️ Corresponding function method is added in the methods option
Or we could call it a mixin but then we might run into some of the same problems that we’ve been talking about before, and of course we can avoid these problems by defining a variable with a prefix of Mixin_ like Mixin_xxx so that when we use this variable we know, oh, this is a mixin, Instead of going through all the files and finding out he’s a mixin
Here’s a good example of what composition-API can do with an old image
Some people might look at this and be confused, and say, “Hey, boy, I don’t see much change in the amount of code you have compared to these two.”
But we can actually view the code on the right by color like this
setup(props,ctx){
// Is it clearer than mixins
const { username,login } = useLogin()
const { pageNum, total, pageSize, getList } = usePagination()
const { xxx, XXX } = useXxx()
}
Copy the code
Why can we view it that way?
So you need to start with ref and Reactive
Ref, reactive
In the Options API, if we want variables to be reactive, we need to define variables in data(), but in setup() we can use ref or reactive anywhere in the setup body to convert variables to reactive
setup(){
// We can define a variable here first
const dataList = ref([])
dataList.value = getList()
// Assuming that our code is very long, and if certain conditions are met, we can then define a variable, without having to go back to data() and re-define a variable reactive
const message = ref(' ')
message.value = getMessage()
// Of course, if you are used to the Options API or your company's own specification expects variables to be defined in the same area. So you could write it this way
const data = reactive({
dataList: [].message:' '
})
data.dataList = getList()
data.message = getMessage()
}
Copy the code
If you are careful, you may have noticed that ref and Reactive perform slightly different data operations on them. Why does ref need to use.value to access data? This is where ref and Reactive are described in the official documentation
In Vue3 you can make any variable reactive via the ref function, as defined in Vue2’s data()
import { ref } from 'vue'
const counter = ref(0)
Copy the code
Ref takes a parameter and returns an object wrapped around a property named value that we can access or change
import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) / / 0
counter.value++
console.log(counter.value) / / 1
Copy the code
So why does this ref have to be so complicated, and add a layer of packets? The following is a classic GIF from the official website, which vividly explains how to do this for magic
This is to keep the behavior of different types of data consistent in JavaScript. Because in JavaScript, basic types like Number and String are passed by value, not by reference.
So if we wrap this variable around and turn it into an object, then we can safely pass it around the entire App without worrying about losing its responsiveness somewhere along the way.
In other words, what the REF does with our variable is create a responsive reference, the concept of which will come up a lot during the use of comaction-API.
Now back to our code above,
// index.js
export default defineComponent({
setup(props,ctx){
// Is it clearer than mixins
const { username,login } = useLogin()
const { pageNum, total, pageSize, getList } = usePagination()
const { xxx, XXX } = useXxx()
}
})
Copy the code
When we pull out the common code and apply these ‘mixins’, is it clearer than mixins
// usePagination.js
export default function usePagination(){
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);
const getList = () = > {
// some logic...
}
return {
pageNum,
pageSize,
total,
getList
}
}
Copy the code
Here we rely on the ref to create the reference through our composite API.
Note that if you want to use variables in the template, you need to return them, and variables created by ref do not need to be accessed using.value, which is automatically unwrapped
Setup()
In setup we have two parameters that we can use: props and context. What are these parameters
Props
Props is the prop value that our parent component passes to our child component. We need to call them with this parameter in setup because this is not available in Setup and does not refer directly to the Vue instance
export default defineComponent({
props: {
searchTemplate: {
type: Array.required: true}},setup(props){
// You can do this directly
console.log(props.searchTemplate)
}
})
Copy the code
This property is responsive when you use props. This property changes when the parent component changes, but it becomes unresponsive when you want to use ES6 deconstruction. If you want to deconstruct the value passed in props, Then you should use toRefs. The thing to note is that it’s accessed by ==. Value ==
export default defineComponent({
props: {
searchTemplate: {
type: Array.required: true}},setup(props){
// You can do this directly
console.log(props.searchTemplate)
/ /
const { searchTemplate } = props
/ /
const { searchTemplate } = toRefs(props)
console.log(searchTemplate.value)
}
})
Copy the code
When your prop is not required, it is indeterminate, you may not get it with toRefs, it will not create a ref, and you will use toRef instead
export default defineComponent({
props: {
searchTemplate: {
type: Array.required: true
},
total: {
type:Number.default:0}},setup(props){
const { total } = toRef(props,'total')
console.log(total.value)
}
})
Copy the code
Context
The second parameter in setup is context. The official Vue3 documentation is a plain JavaScript object that exposes three component properties, attrs, slots, emit. However, using setup in Vue2, There’s more in this context than just these three properties.
Parent, root, process, refs, etc. We can also see how many of these properties are marked with deletion lines on them — parent, root, Listeners, refs, etc. When we mouse over these properties, we will notice that they are deprecated and cannot be used in Vue3. It’s not a bad idea if you want to use it, unless you don’t want to upgrade to Vue3 in the future, my advice is to follow the official protocol and not use these deprecated attributes.
You can also use deconstruction to get these three properties, because context is just a normal object
export default {
setup(props, { attrs, slots, emit }){... }}Copy the code
The component instance is not created when setup is executed. Setup is between beforeCreate and Created. In other words, you can only access the following properties in Setup
-
props
-
attrs
-
slots
-
emit
In other words, you can’t access Data, computed, methods, and setup without this, and you can’t access ~ ~ if you want to
this
If you can’t get this in setup, how do I call the prototype method
In Vue3, it is not recommended to bind methods directly to Prototype. Instead, we have changed the API to . This API gives us access to internal component instances, so let’s console.log
to see what’s inside
Ho, good guy, things can be really many ah, we point into this proxy to see
$message, $confirm, and all the attributes in the context are present in the proxy, whether they are obsolete or available. Some students may ask, but I don’t see any methods related to elements, such as $message, $confirm. There’s nothing here. Let’s look at its parent
Seeing not only Element’s methods, but also some of Vue’s own API methods, how can we use this proxy
import {
ComponentInternalInstance,
defineComponent,
getCurrentInstance,
} from '@vue/composition-api';
export default defineComponent({
setup(){
const { proxy } = getCurrentInstance()
}
})
Copy the code
We could just deconstruct it, but then there would be an error in TypeScript
My idea is to use type assertion const {proxy} = getCurrentInstance () as ComponentInternalInstance, $message; $router. Push; Then I recommend you go back to your options API directly, you can for the proxy renaming, such as const {proxy: _this} = getCurrentInstance () as ComponentInternalInstance in this way, Doesn’t look much different, does it?
LifeCycle
The life cycle in Setup is a little different from the traditional Options API. There is no created or beforeCreate in Setup. In Setup, you print a paragraph on the console and setup is executed between the two
As for the other lifecycle hook functions, vue renamed them to be more semantic
Options API | Hook inside setup |
---|---|
beforeCreate |
Not needed* |
created |
Not needed* |
beforeMount |
onBeforeMount |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeUnmount |
onBeforeUnmount |
unmounted |
onUnmounted |
errorCaptured |
onErrorCaptured |
renderTracked |
onRenderTracked |
renderTriggered |
onRenderTriggered |
activated |
onActivated |
deactivated |
onDeactivated |
Some potholes
$emit is not triggered at all, although vetur has a hint to use it when calling the $emit method with context.root
2. Do not return a value deconstructed from getCurrentInstance in a return, otherwise it will cause an error. See this issue for details
3. Because Vue2 and Vue3 are implemented in a slightly different way, the variables defined by Reactive will be slightly different. If they are modified directly, the variables may not be reactive, and it is better to use REF instead
Reactive ([1, 2, 3]) VS ref ([])
This issue is quite clear
The last
I can only say that I am looking forward to the 2.7 release that Vue Conf says will be released in Q3. Using composite apis in 2.6 is generally not a problem and is much more fun to use than mixins.