Convert Figma logo to code with AI

vuejs logocomposition-api

Composition API plugin for Vue 2

4,191
343
4,191
1

Top Related Projects

207,677

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core

95,657

Deliver web apps with confidence 🚀

78,194

Cybernetically enhanced web apps

36,546

⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.

32,270

A declarative, efficient, and flexible JavaScript library for building user interfaces.

Quick Overview

The Vue Composition API is a set of additive, function-based APIs that allow flexible composition of component logic in Vue.js applications. It provides a way to organize and reuse code in Vue components, offering an alternative to the Options API for more complex scenarios and better TypeScript support.

Pros

  • Improved code organization and reusability
  • Better TypeScript support and type inference
  • More flexible logic composition and sharing between components
  • Easier to extract and test business logic

Cons

  • Steeper learning curve for developers familiar with the Options API
  • Potential for increased verbosity in simpler components
  • Mixing Composition API with Options API can lead to confusion
  • Requires Vue 3 or a plugin for Vue 2, which may complicate existing projects

Code Examples

  1. Basic setup with reactive data:
import { ref, computed } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const doubleCount = computed(() => count.value * 2)

    function increment() {
      count.value++
    }

    return {
      count,
      doubleCount,
      increment
    }
  }
}
  1. Using lifecycle hooks:
import { onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    onMounted(() => {
      console.log('Component mounted')
    })

    onUnmounted(() => {
      console.log('Component unmounted')
    })
  }
}
  1. Extracting reusable logic:
import { ref, watch } from 'vue'

function useSearch(initialQuery = '') {
  const searchQuery = ref(initialQuery)
  const results = ref([])

  watch(searchQuery, async (newQuery) => {
    results.value = await fetchSearchResults(newQuery)
  })

  return {
    searchQuery,
    results
  }
}

export default {
  setup() {
    const { searchQuery, results } = useSearch()

    return {
      searchQuery,
      results
    }
  }
}

Getting Started

To use the Composition API in a Vue 3 project:

  1. Install Vue 3:

    npm install vue@next
    
  2. In your component file:

    import { ref, computed } from 'vue'
    
    export default {
      setup() {
        const message = ref('Hello, Composition API!')
        const reversedMessage = computed(() => message.value.split('').reverse().join(''))
    
        return {
          message,
          reversedMessage
        }
      }
    }
    
  3. Use the component in your template as usual.

Competitor Comparisons

207,677

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core

Pros of Vue

  • More mature and stable ecosystem with extensive documentation
  • Wider adoption and community support
  • Includes both Options API and Composition API, offering flexibility

Cons of Vue

  • Larger bundle size due to inclusion of both APIs
  • Steeper learning curve for beginners due to multiple ways of doing things
  • Slower release cycle for new features

Code Comparison

Vue (Options API):

export default {
  data() {
    return { count: 0 }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}

Composition API:

import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const increment = () => count.value++
    return { count, increment }
  }
}

Key Differences

  • Composition API focuses on composable functions, while Vue core includes both APIs
  • Composition API allows for better code organization and reusability
  • Vue core provides a more complete framework experience out of the box

Use Cases

  • Choose Vue for full-featured applications with diverse requirements
  • Opt for Composition API when building complex, logic-heavy components or when migrating from Vue 2 to Vue 3

Community and Support

  • Vue has a larger community and more third-party libraries
  • Composition API is gaining traction, especially among experienced Vue developers
95,657

Deliver web apps with confidence 🚀

Pros of Angular

  • Full-featured framework with built-in tools for routing, forms, and HTTP requests
  • Dependency injection system for better modularity and testability
  • TypeScript support out of the box, providing strong typing and improved tooling

Cons of Angular

  • Steeper learning curve due to its comprehensive nature and unique concepts
  • Larger bundle size compared to Vue's Composition API
  • More opinionated structure, which may limit flexibility in some cases

Code Comparison

Angular component:

@Component({
  selector: 'app-example',
  template: `<h1>{{ title }}</h1>`
})
export class ExampleComponent {
  title = 'Hello Angular';
}

Vue Composition API:

import { ref } from 'vue';

export default {
  setup() {
    const title = ref('Hello Vue');
    return { title };
  }
}

Summary

Angular is a comprehensive framework offering a full suite of tools and features, while Vue's Composition API focuses on providing a flexible and lightweight approach to building components. Angular's structure and tooling can be beneficial for large-scale applications, but it comes with a steeper learning curve. The Composition API offers a more intuitive and less opinionated way to organize component logic, making it easier to adopt and use in various project sizes.

78,194

Cybernetically enhanced web apps

Pros of Svelte

  • Smaller bundle sizes due to compile-time optimization
  • Simpler syntax with less boilerplate code
  • Built-in state management without additional libraries

Cons of Svelte

  • Smaller ecosystem and community compared to Vue
  • Less flexibility for complex applications
  • Limited tooling and IDE support

Code Comparison

Svelte component:

<script>
  let count = 0;
  function increment() {
    count += 1;
  }
</script>

<button on:click={increment}>
  Clicks: {count}
</button>

Vue Composition API component:

<template>
  <button @click="increment">
    Clicks: {{ count }}
  </button>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const increment = () => {
      count.value++
    }
    return { count, increment }
  }
}
</script>

Svelte offers a more concise syntax, with reactive variables and event handling built into the language. The Vue Composition API provides a more explicit approach to reactivity and component logic organization, which can be beneficial for larger applications.

36,546

⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.

Pros of Preact

  • Smaller bundle size and faster performance
  • Closer to vanilla JavaScript, with a simpler API
  • Compatible with many React libraries and components

Cons of Preact

  • Smaller ecosystem and community compared to Vue
  • Less comprehensive documentation and learning resources
  • Fewer built-in features and tools for complex applications

Code Comparison

Preact:

import { h, render } from 'preact';

function App() {
  return <h1>Hello, World!</h1>;
}

render(<App />, document.body);

Composition API:

<script setup>
import { h } from 'vue'

const App = () => h('h1', 'Hello, World!')
</script>

<template>
  <App />
</template>

Key Differences

  • Preact uses a more React-like syntax, while Composition API is Vue-specific
  • Preact has a smaller learning curve for developers familiar with React
  • Composition API offers more flexibility in organizing component logic
  • Preact focuses on simplicity and performance, while Composition API aims to enhance Vue's reactivity system

Use Cases

  • Preact: Lightweight applications, progressive enhancement, performance-critical projects
  • Composition API: Complex Vue applications, large-scale projects, when leveraging Vue's ecosystem
32,270

A declarative, efficient, and flexible JavaScript library for building user interfaces.

Pros of Solid

  • Smaller bundle size and better performance due to its compilation approach
  • No virtual DOM, resulting in faster rendering and updates
  • Fine-grained reactivity without the need for hooks or lifecycle methods

Cons of Solid

  • Smaller ecosystem and community compared to Vue
  • Steeper learning curve for developers familiar with traditional frameworks
  • Less mature tooling and documentation

Code Comparison

Solid:

import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);
  return <button onClick={() => setCount(count() + 1)}>{count()}</button>;
}

Vue Composition API:

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
  <button @click="count++">{{ count }}</button>
</template>

Both examples demonstrate a simple counter component, showcasing the different approaches to reactivity and state management in Solid and Vue Composition API. Solid uses signals and fine-grained reactivity, while Vue Composition API utilizes ref for reactive state.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

@vue/composition-api

Vue 2 plugin for Composition API

npm GitHub Workflow Status Minzipped size

English | 中文 ・ Composition API Docs

⚠️ With the release of Vue 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.

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'

: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.7.2"></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

:white_check_mark: Support     :x: 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: 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.

:bulb: In Vue 3, it will return a 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 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.component('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: 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.

:bulb: In Vue 3, it will return a 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 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.

NPM DownloadsLast 30 Days