Nonstick Pancake Maker

    @vue/composition-api
    TypeScript icon, indicating that this package has built-in type declarations

    1.6.3 • Public • Published

    @vue/composition-api

    Vue 2 plugin for Composition API

    npm GitHub Workflow Status Minzipped size

    English | 中文Composition API Docs

    Installation

    NPM

    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 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.6.3"></script>

    @vue/composition-api will be exposed to global variable window.VueCompositionAPI.

    const { ref, reactive } = VueCompositionAPI

    TypeScript Support

    TypeScript version >4.2 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
    })

    JSX/TSX

    JSX is now officially supported on vuejs/jsx. You can enable it by following this document. A community maintained version can be found at babel-preset-vca-jsx by @luwanquan.

    To support TSX, create a declaration file with the following content in your project.

    // file: shim-tsx.d.ts
    import Vue, { VNode } from 'vue';
    import { ComponentRenderProxy } from '@vue/composition-api';
    
    declare global {
      namespace JSX {
        interface Element extends VNode {}
        interface ElementClass extends ComponentRenderProxy {}
        interface ElementAttributesProperty {
          $props: any; // specify the property name to use
        }
        interface IntrinsicElements {
          [elem: string]: any;
        }
      }
    }

    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,
        }
      }
    }

    Browser Compatibility

    @vue/composition-api supports all modern browsers and IE11+. For lower versions IE you should install WeakMap polyfill (for example from core-js package).

    Limitations

    Support      Not Supported

    Ref Unwrap

    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

    Template Refs

    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: 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(() => {
          // 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" />
      },
    }

    Reactive

    ⚠️ 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.

    ⚠️ set and del workaround for adding and deleting reactive properties

    ⚠️ Warning: set and del do NOT exist in Vue 3. We provide them as a workaround here, due to the limitation of Vue 2.x reactivity system.

    In Vue 2, you will need to call set to track new keys on an object(similar to Vue.set but for reactive 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 to ensure a key deletion triggers view updates in reactive objects (similar to Vue.delete but for reactive objects created by the Composition API). In Vue 3 you can just delete them by calling delete foo.bar.

    import { reactive, set, del } from '@vue/composition-api'
    
    const a = reactive({
      foo: 1
    })
    
    // add new reactive key
    set(a, 'bar', 1)
    
    // remove a key and trigger reactivity
    del(a, 'bar')

    Watch

    onTrack and onTrigger are not available in WatchOptions
    watch(() => {
        /* ... */
    }, {
      immediate: true,
      onTrack() {}, // not available
      onTrigger() {}, // not available
    })

    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) // equivalent to Vue.component('Foo', Foo)
    app1.use(VueRouter) // equivalent to Vue.use(VueRouter)
    
    const app2 = createApp(RootComponent2)
    app2.component('Bar', Bar) // equivalent to Vue.use('Bar', Bar)

    createElement / h

    ⚠️ createElement / h workaround

    createElement / h in Vue 2 is only accessable in render() function. To use it outside of render(), 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 { h as _h } from '@vue/composition-api'
    
    export default {
      setup() {
        const vm = getCurrentInstance()
        const h = _h.bind(vm)
    
        return () =>
          h('div', {
            ref: 'root',
          })
      },
    }

    shallowReadonly

    ⚠️ shallowReadonly() will create a new object and with the same root properties, new properties added will not be readonly or reactive.

    💡 In Vue 3, it will return an new proxy object.

    readonly

    ⚠️ readonly() provides only type-level readonly check.

    readonly() is provided as API alignment with Vue 3 on type-level only. Use isReadonly() on it or it's properties can not be guaranteed.

    props

    ⚠️ 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 instead
        const { foo } = toRefs(props)
        const a = foo.value.bar
      }
    })

    computed().effect

    ⚠️ computed() has a property effect set to true instead of a ReactiveEffect.

    Due to the difference in implementation, there is no such concept as a ReactiveEffect in @vue/composition-api. Therefore, effect is merely true to enable differentiating computed from refs:

    function isComputed<T>(o: ComputedRef<T> | unknown): o is ComputedRef<T>
    function isComputed(o: any): o is ComputedRef {
      return !!(isRef(o) && o.effect)
    }

    Missing APIs

    The following APIs introduced in Vue 3 are not available in this plugin.

    • onRenderTracked
    • onRenderTriggered
    • isProxy

    Reactive APIs in data()

    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),
        }
      },
    }

    emits Options

    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 effects
        submit: (eventOption) => {
          if (...) {
            return true
          } else {
            console.warn('Invalid submit event payload!')
            return false
          }
        }
      }
    })

    Performance Impact

    Due the 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 the benchmark results for more details.

    Install

    npm i @vue/composition-api

    DownloadsWeekly Downloads

    351,641

    Version

    1.6.3

    License

    MIT

    Unpacked Size

    406 kB

    Total Files

    12

    Last publish

    Collaborators

    • soda
    • linusborg
    • antfu
    • pikax