@vue/composition-api
Vue 2 plugin for Composition API
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vuejs/composition-api/Build%20&%20Test)
English | 中文 ・ Composition API Docs
Installation
NPM
npm install @vue/composition-api
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)
import { ref, reactive } from '@vue/composition-api'
:bulb: When you migrate to Vue 3, just replacing @vue/composition-api
to vue
and your code should just work.
CDN
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@1.0.0-beta.4"></script>
@vue/composition-api
will be exposed to global variable window.VueCompositionAPI
.
const { ref, reactive } = VueCompositionAPI
TypeScript Support
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({
})
JSX/TSX
To make JSX/TSX work with @vue/composition-api
, check out babel-preset-vca-jsx by @luwanquan.
SSR
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,
}
},
};
Limitations
:white_check_mark: Support :x: Not Supported
Ref
Unwrap
Unwrap
is not working with Array index.
❌ Should NOT store ref
as a direct child of Array
const state = reactive({
list: [ref(0)],
})
state.list[0].value === 0
state.list.push(ref(1))
state.list[1].value === 1
❌ Should NOT use ref
in a plain object when working with Array
const a = {
count: ref(0),
}
const b = reactive({
list: [a],
})
b.list[0].count.value === 0
const b = reactive({
list: [
{
count: ref(0),
},
],
})
b.list[0].count.value === 0
✅ Should always use ref
in a reactive
when working with Array
const a = reactive({
list: [
reactive({
count: ref(0),
})
],
})
a.list[0].count === 0
a.list.push(
reactive({
count: ref(1),
})
)
a.list[1].count === 1
Template Refs
✅ String ref && return it from setup()
<template>
<div ref="root"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
onMounted(() => {
console.log(root.value)
})
return {
root,
}
},
}
</script>
✅ String ref && return it from setup()
&& Render Function / JSX
export default {
setup() {
const root = ref(null)
onMounted(() => {
console.log(root.value)
})
return {
root,
}
},
render() {
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,
})
return () => <div ref={root} />
},
}
⚠️ $refs
accessing workaround
:warning: Warning: The SetupContext.refs
won't exist in Vue 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(() => {
console.log(refs.root)
})
return () =>
h('div', {
ref: 'root',
})
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
⚠️ reactive()
mutates the original object
reactive
uses Vue.observable
underneath which will mutate the original object.
:bulb: In Vue 3, it will return an new proxy object.
Watch
❌ onTrack
and onTrigger
are not available in WatchOptions
watch(() => {
}, {
immediate: true,
onTrack() {},
onTrigger() {},
})
createApp
⚠️ createApp()
is global
In Vue 3, createApp()
is introduced to provide context(plugin, components, etc.) isolation between app instances. Due the the design of Vue 2, in this plugin, we provide createApp()
as a forward compatible API which is just an alias of the global.
const app1 = createApp(RootComponent1)
app1.component('Foo', Foo)
app1.use(VueRouter)
const app2 = createApp(RootComponent2)
app2.component('Bar', Bar)
Missing APIs
The following APIs introduced in Vue 3 are not available in this plugin.
readonly
shallowReadonly
defineAsyncComponent
onRenderTracked
onRenderTriggered
isProxy
isReadonly
isVNode
Reactive APIs in data()
❌ Passing ref
, reactive
or other reactive apis to data()
would not work.
export default {
data() {
return {
a: ref(1)
}
},
}
Performance Impact
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.