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:
@vue/composition-api
Common API usage- Vue3 code logic extraction and reuse
- How to use
provide+inject
alternativevuex
plan
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({ number: 0 })
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({ count: 0 })
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({ count: 0 })
let countRef = toRef(state, 'count')
let state2 = reactive({ count2: 0 })
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