- Notifications
You must be signed in to change notification settings - Fork342
Composition API plugin for Vue 2
License
vuejs/composition-api
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Vue 2 plugin forComposition API
English |中文 ・Composition API Docs
⚠️ With the release ofVue 2.7, which has Composition API built-in,you no longer need this plugin. Thereby this plugin has entered maintenance mode and will only support Vue 2.6 or earlier. This project will reach End of Life by the end of 2022.
npm install @vue/composition-api# oryarn add @vue/composition-api
You must install@vue/composition-api
as a plugin viaVue.use()
before you can use theComposition API to compose your component.
importVuefrom'vue'importVueCompositionAPIfrom'@vue/composition-api'Vue.use(VueCompositionAPI)
// use the APIsimport{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.
<scriptsrc="https://cdn.jsdelivr.net/npm/vue@2.6"></script><scriptsrc="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.7.2"></script>
@vue/composition-api
will be exposed to global variablewindow.VueCompositionAPI
.
const{ ref, reactive}=VueCompositionAPI
TypeScript version>4.2 is required
To let TypeScript properly infer types inside Vue component options, you need to define components withdefineComponent
import{defineComponent}from'@vue/composition-api'exportdefaultdefineComponent({// type inference enabled})
JSX is now officially supported onvuejs/jsx. You can enable it by followingthis document. A community maintained version can be found atbabel-preset-vca-jsx by@luwanquan.
To support TSX, create a declaration file with the following content in your project.
// file: shim-tsx.d.tsimportVue,{VNode}from'vue';import{ComponentRenderProxy}from'@vue/composition-api';declare global{namespaceJSX{interfaceElementextendsVNode{}interfaceElementClassextendsComponentRenderProxy{}interfaceElementAttributesProperty{$props:any;// specify the property name to use}interfaceIntrinsicElements{[elem:string]:any;}}}
Even if there is no definitive Vue 3 API for SSR yet, this plugin implements theonServerPrefetch
lifecycle hook that allows you to use theserverPrefetch
hook found in the classic API.
import{onServerPrefetch}from'@vue/composition-api'exportdefault{setup(props,{ ssrContext}){constresult=ref()onServerPrefetch(async()=>{result.value=awaitcallApi(ssrContext.someId)})return{ result,}}}
@vue/composition-api
supports all modern browsers and IE11+. For lower versions IE you should installWeakMap
polyfill (for example fromcore-js
package).
✅ Support ❌ Not Supported
❌Should NOT useref
in a plain object when working withArray
consta={count:ref(0),}constb=reactive({list:[a],// `a.count` will not unwrap!!})// no unwrap for `count`, `.value` is requiredb.list[0].count.value===0// true
constb=reactive({list:[{count:ref(0),// no unwrap!!},],})// no unwrap for `count`, `.value` is requiredb.list[0].count.value===0// true
✅Should always useref
in areactive
when working withArray
consta=reactive({list:[reactive({count:ref(0),}),]})// unwrappeda.list[0].count===0// truea.list.push(reactive({count:ref(1),}))// unwrappeda.list[1].count===1// true
✅ String ref && return it fromsetup()
<template><divref="root"></div></template><script>exportdefault{setup(){constroot=ref(null)onMounted(()=>{// the DOM element will be assigned to the ref after initial renderconsole.log(root.value)// <div/>})return{ root,}},}</script>
✅ String ref && return it fromsetup()
&& Render Function / JSX
exportdefault{setup(){constroot=ref(null)onMounted(()=>{// the DOM element will be assigned to the ref after initial renderconsole.log(root.value)// <div/>})return{ root,}},render(){// with JSXreturn()=><divref="root"/>},}
❌ Function ref
<template><div:ref="el => root = el"></div></template><script>exportdefault{setup(){constroot=ref(null)return{ root,}},}</script>
❌ Render Function / JSX insetup()
exportdefault{setup(){constroot=ref(null)return()=>h('div',{ref:root,})// with JSXreturn()=><divref={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 accessvm.$refs
viaSetupContext.refs
exportdefault{setup(initProps,setupContext){constrefs=setupContext.refsonMounted(()=>{// the DOM element will be assigned to the ref after initial renderconsole.log(refs.root)// <div/>})return()=>h('div',{ref:'root',})// with JSXreturn()=><divref="root"/>},}
⚠️ reactive()
mutates the original object
reactive
usesVue.observable
underneath which willmutate the original object.
💡 In Vue 3, it will return a new proxy object.
⚠️ set
anddel
workaround for adding and deleting reactive properties
⚠️ Warning:set
anddel
do NOT exist in Vue 3. We provide them as a workaround here, due to the limitation ofVue 2.x reactivity system.In Vue 2, you will need to call
set
to track new keys on anobject
(similar toVue.set
but forreactive objects
created by the Composition API). In Vue 3, you can just assign them like normal objects.Similarly, in Vue 2 you will need to call
del
toensure a key deletion triggers view updates in reactive objects (similar toVue.delete
but forreactive objects
created by the Composition API). In Vue 3 you can just delete them by callingdelete foo.bar
.
import{reactive,set,del}from'@vue/composition-api'consta=reactive({foo:1})// add new reactive keyset(a,'bar',1)// remove a key and trigger reactivitydel(a,'bar')
❌onTrack
andonTrigger
are not available inWatchOptions
watch(()=>{/* ... */},{immediate:true,onTrack(){},// not availableonTrigger(){},// not available})
⚠️ createApp()
is global
In Vue 3,createApp()
is introduced to provide context(plugin, components, etc.) isolation between app instances. Due the design of Vue 2, in this plugin, we providecreateApp()
as a forward compatible API which is just an alias of the global.
constapp1=createApp(RootComponent1)app1.component('Foo',Foo)// equivalent to Vue.component('Foo', Foo)app1.use(VueRouter)// equivalent to Vue.use(VueRouter)constapp2=createApp(RootComponent2)app2.component('Bar',Bar)// equivalent to Vue.component('Bar', Bar)
⚠️ createElement
/h
workaround
createElement
/h
in Vue 2 is only accessable inrender()
function. To use it outside ofrender()
, you can explicitly bind a component instance to it.
⚠️ Warning: This ability is provided as a workaround Vue 2, it's not part of the Vue 3 API.
import{has_h}from'@vue/composition-api'exportdefault{setup(){constvm=getCurrentInstance()consth=_h.bind(vm)return()=>h('div',{ref:'root',})},}
⚠️ shallowReadonly()
will create a new object and with the same root properties, new properties added willnot be readonly or reactive.
💡 In Vue 3, it will return a new proxy object.
⚠️ readonly()
providesonly type-level readonly check.
readonly()
is provided as API alignment with Vue 3 on type-level only. UseisReadonly()
on it or it's properties can not be guaranteed.
⚠️ toRefs(props.foo)
will incorrectly warn when accessing nested levels of props.
⚠️ isReactive(props.foo)
will return false.
defineComponent({setup(props){const{ bar}=toRefs(props.foo)// it will `warn`// use this insteadconst{ foo}=toRefs(props)consta=foo.value.bar}})
⚠️ computed()
has a propertyeffect
set totrue
instead of aReactiveEffect
.
Due to the difference in implementation, there is no such concept as aReactiveEffect
in@vue/composition-api
. Therefore,effect
is merelytrue
to enable differentiating computed from refs:
functionisComputed<T>(o:ComputedRef<T>|unknown):o isComputedRef<T>functionisComputed(o:any):o isComputedRef{return!!(isRef(o)&&o.effect)}
The following APIs introduced in Vue 3 are not available in this plugin.
onRenderTracked
onRenderTriggered
isProxy
❌ Passingref
,reactive
or other reactive apis todata()
would not work.
exportdefault{data(){return{// will result { a: { value: 1 }} in templatea:ref(1),}},}
❌emits
option is provided in type-level only, in order to align with Vue 3's type interface. Does NOT have actual effects on the code.
defineComponent({emits:{// has no effectssubmit:(eventOption)=>{if(...){ returntrue}else{console.warn('Invalid submit event payload!')returnfalse}}}})
Due the limitation of Vue2's public API.@vue/composition-api
inevitably introduces some performance overhead. Note that in most scenarios, this shouldn't be the source of performance issues.
You can check thebenchmark results for more details.
About
Composition API plugin for Vue 2
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.