Vue 2 plugin for Composition API
English | 中文 ・ Composition API Docs
Note: the primary goal of this package is to allow the community to experiment with the API and provide feedback before it's finalized. The implementation may contain minor inconsistencies with the RFC as the latter gets updated. We do not recommend using this package for production yet at this stage.
npm install @vue/composition-api
# or
yarn add @vue/composition-api
You must install @vue/composition-api
as a plugin via Vue.use()
before you can use the Composition API to compose your component.
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
// use the APIs
import { ref, reactive } from '@vue/composition-api'
💡 When you migrate to Vue 3, just replacing
@vue/composition-api
tovue
and your code should just work.
Include @vue/composition-api
after Vue and it will install itself automatically.
<script src="https://cdn.jsdelivr.net/npm/vue@2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@0.6.7"></script>
@vue/composition-api
will be exposed to global variable window.vueCompositionApi
.
const { ref, reactive } = vueCompositionApi
TypeScript version >3.5.1 is required
To let TypeScript properly infer types inside Vue component options, you need to define components with defineComponent
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
// type inference enabled
})
To make JSX/TSX work with @vue/composition-api
, check out babel-preset-vca-jsx by @luwanquan.
Even if there is no definitive Vue 3 API for SSR yet, this plugin implements the onServerPrefetch
lifecycle hook that allows you to use the serverPrefetch
hook found in the classic API.
import { onServerPrefetch } from '@vue/composition-api'
export default {
setup (props, { ssrContext }) {
const result = ref()
onServerPrefetch(async () => {
result.value = await callApi(ssrContext.someId)
})
return {
result,
}
},
};
✅ Support ❌ Not Supported
Unwrap
is not working with Array index.
❌ Should NOT store ref
as a direct child of Array
const state = reactive({
list: [ref(0)],
})
// no unwrap, `.value` is required
state.list[0].value === 0 // true
state.list.push(ref(1))
// no unwrap, `.value` is required
state.list[1].value === 1 // true
❌ Should NOT use ref
in a plain object when working with Array
const a = {
count: ref(0),
}
const b = reactive({
list: [a], // `a.count` will not unwrap!!
})
// no unwrap for `count`, `.value` is required
b.list[0].count.value === 0 // true
const b = reactive({
list: [
{
count: ref(0), // no unwrap!!
},
],
})
// no unwrap for `count`, `.value` is required
b.list[0].count.value === 0 // true
✅ Should always use ref
in a reactive
when working with Array
const a = reactive({
list: [
reactive({
count: ref(0),
})
],
})
// unwrapped
a.list[0].count === 0 // true
a.list.push(
reactive({
count: ref(1),
})
)
// unwrapped
a.list[1].count === 1 // true
✅ String ref && return it from setup()
<template>
<div ref="root"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value) // <div/>
})
return {
root,
}
},
}
</script>
✅ String ref && return it from setup()
&& Render Function / JSX
export default {
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value) // <div/>
})
return {
root,
}
},
render() {
// with JSX
return () => <div ref="root" />
},
}
❌ Function ref
<template>
<div :ref="el => root = el"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
return {
root,
}
},
}
</script>
❌ Render Function / JSX in setup()
export default {
setup() {
const root = ref(null)
return () =>
h('div', {
ref: root,
})
// with JSX
return () => <div ref={root} />
},
}
⚠️ $refs
accessing workaround
⚠️ Warning: TheSetupContext.refs
won't exist inVue 3.0
.@vue/composition-api
provide it as a workaround here.
If you really want to use template refs in this case, you can access vm.$refs
via SetupContext.refs
export default {
setup(initProps, setupContext) {
const refs = setupContext.refs
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(refs.root) // <div/>
})
return () =>
h('div', {
ref: 'root',
})
// with JSX
return () => <div ref="root" />
},
}
You may also need to augment the SetupContext
when working with TypeScript:
import Vue from 'vue'
declare module '@vue/composition-api' {
interface SetupContext {
readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] }
}
}
⚠️ reactive()
mutates the original object
reactive
uses Vue.observable
underneath which will mutate the original object.
💡 In Vue 3, it will return an new proxy object.
❌ onTrack
and onTrigger
are not available in WatchOptions
watch(() => {
/* ... */
}, {
immediate: true,
onTrack() {}, // not available
onTrigger() {}, // not available
})
The following APIs introduced in Vue 3 are not available in this plugin.
readonly
shallowReadonly
defineAsyncComponent
onRenderTracked
onRenderTriggered
customRef
isProxy
isReadonly
isVNode
❌ Passing ref
, reactive
or other reactive apis to data()
would not work.
export default {
data() {
return {
// will result { a: { value: 1 } } in template
a: ref(1)
}
},
}
Due the the limitation of Vue2's public API. @vue/composition-api
inevitably introduced some extract costs. It shouldn't bother you unless in extreme environments.
You can check the benchmark results for more details.