UNPKG

@aimwhy/vue-function-api

Version:

Vue2 plugin for the function-based RFC

345 lines (262 loc) 7.72 kB
# Vue Function API > [Function-based Component API RFC](https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md) Future-Oriented Programming, `@aimwhy/vue-function-api` provides function api from `Vue3.x` to `Vue2.x` for developing next-generation Vue applications. [**中文文档**](./README.zh-CN.md) --- # Navigation - [Changelog](https://github.com/aimwhy/vue-function-api/blob/master/CHANGELOG.md) - [Installation](#Installation) - [Usage](#Usage) - [Example](#Example) - [Single-File Component](#single-file-Component) - [Demo](https://codesandbox.io/s/vue-template-szw4b) - [API](#API) - [setup](#setup) - [value](#value) - [state](#state) - [computed](#computed) - [watch](#watch) - [lifecycle](#lifecycle) - [provide, inject](#provide-inject) - [Misc](#Misc) # Installation **npm** ```bash npm install @aimwhy/vue-function-api --save ``` **yarn** ```bash yarn add @aimwhy/vue-function-api ``` **CDN** ```html <script src="https://unpkg.com/@aimwhy/vue-function-api@0.0.6/dist/index.js"></script> ``` By using the global variable `window.vueFunctionApi` # Usage You must explicitly install `@aimwhy/vue-function-api` via `Vue.use()`: ```js import Vue from 'vue' import { plugin } from '@aimwhy/vue-function-api' Vue.use(plugin) ``` After installing the plugin you can use the new [function API](#API) to compose your component. # Example ## Single-File Component ``` html <template> <div> <span>count is {{ count }}</span> <span>plusOne is {{ plusOne }}</span> <button @click="increment">count++</button> </div> </template> <script> import Vue from 'vue'; import { value, computed, watch, onMounted } from '@aimwhy/vue-function-api' export default { setup() { // reactive state const count = value(0); // computed state const plusOne = computed(() => count.value + 1); // method const increment = () => { count.value++; }; // watch watch( () => count.value * 2, val => { console.log(`count * 2 is ${val}`); } ); // lifecycle onMounted(() => { console.log(`mounted`); }); // expose bindings on render context return { count, plusOne, increment, }; }, }; </script> ``` # API ## setup**setup**(props: *`Props`*, context: *[`Context`](#Context)*): `Object|undefined` A new component option, `setup()` is introduced. As the name suggests, this is the place where we use the function-based APIs to setup the logic of our component. `setup()` is called when an instance of the component is created, after props resolution. The function receives the resolved props as its first argument. The second argument provides a `context` object which exposes a number of properties that were previously exposed on this in 2.x APIs. ```js const MyComponent = { props: { name: String }, setup(props, context) { console.log(props.name); // context.attrs // context.slots // context.refs // context.emit // context.parent // context.root } } ``` ## value**value**(value: *`any`*): [`Wrapper`][Wrapper] Calling `value()` returns a **value wrapper** object that contains a single reactive property: `.value`. Example: ```js import { value } from '@aimwhy/vue-function-api' const MyComponent = { setup(props) { const msg = value('hello') const appendName = () => { msg.value = `hello ${props.name}` } return { msg, appendName } }, template: `<div @click="appendName">{{ msg }}</div>` } ``` ## state**state**(value: *`any`*) Equivalent with [`Vue.observable`](https://vuejs.org/v2/api/index.html#Vue-observable). Example: ```js import { state } from '@aimwhy/vue-function-api' const object = state({ count: 0 }) object.count++ ``` ## computed**computed**(getter: *`Function`*, setter?: *`Function`*): [`Wrapper`][Wrapper] Equivalent with computed property from `vue 2.x`. Example: ```js import { value, computed } from '@aimwhy/vue-function-api' const count = value(0) const countPlusOne = computed(() => count.value + 1) console.log(countPlusOne.value) // 1 count.value++ console.log(countPlusOne.value) // 2 ``` ## watch**watch**(source: *`Wrapper | () => any`*, callback: *`(newVal, oldVal)`*, options?: *[`WatchOption`](#WatchOption)*): `Function`**watch**(source: *`Array<Wrapper | () => any>`*, callback: *`([newVal1, newVal2, ... newValN], [oldVal1, oldVal2, ... oldValN])`*, options?: *[`WatchOption`](#WatchOption)*): `Function` The `watch` API provides a way to perform side effect based on reactive state changes. **Returns** a `Function` to stop the `watch`. > [effect-cleanup](https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md#effect-cleanup) . ### WatchOption | Name | Type | Default | Description | | ------ | ------ | ------ | ------ | | lazy | `boolean` | `false` | The opposite of 2.x's `immediate` option | | deep | `boolean` | `false` | Same as 2.x | | flush | `"pre"` \| `"post"` \| `"sync"` | `"post"` | `"post"`: fire after renderer flush; `"pre"`: fire before renderer flush; `"sync"`: fire synchronously | Example: ```js watch( // getter () => count.value + 1, // callback (value, oldValue) => { console.log('count + 1 is: ', value) } ) // -> count + 1 is: 1 count.value++ // -> count + 1 is: 2 ``` Example (Multiple Sources): ```js watch( [valueA, () => valueB.value], ([a, b], [prevA, prevB]) => { console.log(`a is: ${a}`) console.log(`b is: ${b}`) } ) ``` ## lifecycle**onCreated**(cb: *`Function`*) ▸ **onBeforeMount**(cb: *`Function`*) ▸ **onMounted**(cb: *`Function`*) ▸ **onXXX**(cb: *`Function`*) All current lifecycle hooks will have an equivalent `onXXX` function that can be used inside `setup()` Example: ```js import { onMounted, onUpdated, onUnmounted } from '@aimwhy/vue-function-api' const MyComponent = { setup() { onMounted(() => { console.log('mounted!') }) onUpdated(() => { console.log('updated!') }) onUnmounted(() => { console.log('unmounted!') }) } } ``` ## provide, inject**provide**(value: *`Object`*) ▸ **inject**(key: *`string` | `symbol`*) Equivalent with `provide` and `inject` from `2.x` Example: ```js import { provide, inject } from '@aimwhy/vue-function-api' const CountSymbol = Symbol() const Ancestor = { setup() { // providing a value can make it reactive const count = value(0) provide({ [CountSymbol]: count }) } } const Descendent = { setup() { const count = inject(CountSymbol) return { count } } } ``` ## Context The `context` object exposes a number of properties that were previously exposed on this in 2.x APIs: ```js const MyComponent = { setup(props, context) { context.attrs context.slots context.refs context.emit context.parent context.root } } ``` Full properties list: * parent * root * refs * slots * attrs * emit # Misc - `@aimwhy/vue-function-api` will keep updated with `Vue3.x` API. When `3.0` released, you can replace this library seamlessly. - `@aimwhy/vue-function-api` only relies on `Vue2.x` itself. Wheather `Vue3.x` is released or not, it's not affect you using this library. - Due the the limitation of `Vue2.x`'s public API. `@aimwhy/vue-function-api` inevitably introduce some extract workload. It doesn't concern you if you are now working on extreme environment. [wrapper]: https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md#why-do-we-need-value-wrappers