Skip to main content

vue2/3 options

Usually, use hook can only be used in vue's setup, but through the helper function provided by @alova/vue-options, you can also use alova's use hook in vue's options, which is perfectly compatible with almost all functions of alova.

Available in both vue2 and vue3.

npm build coverage status typescript license

Install

npm install alova @alova/vue-options --save
alova requirements

alova version >= 2.13.2

Usage

Map hook status and functions to vue instances

First use vueOptionHook to create an alova instance.

import { createAlova, Method } from 'alova';
import GlobalFetch from 'alova/GlobalFetch';
import { VueOptionsHook } from '@alova/vue-options';

// api.js
const alovaInst = createAlova({
baseURL: 'http://example.com',
statesHook: VueOptionsHook,
requestAdapter: GlobalFetch(),
responded: response => response.json()
});

/** @type {() => Method<unknown, unknown, { content: string, time: string }[]>} */
export const getData = () => alovaInst.Get('/todolist');

Then use mapAlovaHook to map the return value set of use hook to the component instance. The following is how to access the reactive state and operation functions:

  1. You can access responsive status such as loading/data/error through the key of the collection, such as this.key.loading, this.key.data.
  2. You can access the operation function through the key of the collection plus the function name, and use $ to splice it, such as this.key$send, this.key$onSuccess.

Below is a complete example.

<template>
<div>
<span role="loading">{{ todoRequest.loading ? 'loading' : 'loaded' }}</span>
<span role="error">{{ todoRequest.error ? todoRequest.error.message : '' }}</span>
<div role="data">{{ JSON.stringify(todoRequest.data) }}</div>
<button
@click="todoRequest$send"
role="btnSend">
send
</button>
</div>
</template>

<script>
import { useRequest } from 'alova';
import { mapAlovaHook } from '@alova/vue-options';
import { getData } from './api';

export default {
// mapAlovaHook will return the mixins array, and the usage of use hook is the same as before
mixins: mapAlovaHook(function (vm) {
// The component instance can be accessed through this or vm
// When using this, this callback function cannot be an arrow function
console.log(this, vm);
return {
todoRequest: useRequest(getData)
};
}),
created() {
this.todoRequest.loading;
this.todoRequest$send();
this.todoRequest$onSuccess(event => {
event.data.match;
event.sendArgs.copyWithin;
});
this.todoRequest$onSuccess(event => {
console.log('success', event);
});
this.todoRequest$onError(event => {
console.log('error', event);
});
},
mounted() {
this.todoRequest$onComplete(event => {
console.log('complete', event);
});
}
};
</script>

Computed properties

If you need to define a computed property that depends on hook-related request status, just write it as usual.

export default {
computed: {
todoRequestLoading() {
return this.todoRequest.loading;
},
todoRequestData() {
return this.todoRequest.data;
}
}
};

Watch hook status changes

Due to the limitations of vue2, all hook states are mounted on an object named alovaHook$, so you need to add the alovaHook$ prefix when listening.

export default {
watch: {
// ❌Unable to watch
'todoRequest.loading'(newVal, oldVal) {
// ...
},
// ✅watching is work
'alovaHook$.todoRequest.loading'(newVal, oldVal) {
// ...
}
}
};

But this is a bit troublesome, so a mapWatcher helper function is provided, which can not only automatically add prefixes, nested watching, but also batch watching.

Define single watch handler

export default {
watch: mapWatcher({
// Usage 1
'todoRequest.loading'(newVal, oldVal) {},

// Usage 2
todoRequest: {
loading(newVal, oldVal) {},
data(newVal, oldVal) {}
}
})
};

Watching object is also supported.

export default {
watch: mapWatcher({
todoRequest: {
data: {
handler(newVal, oldVal) {},
deep: true
}
}
})
};

Batch define watch handlers

Multiple watching keys are separated by ,.

export default {
watch: mapWatcher({
// Usage 1
'todoRequest1.data, todoRequest2.data'(newVal, oldVal) {},

// Usage 2
'todoRequest1, todoRequest2': {
loading(newVal, oldVal) {},
data(newVal, oldVal) {}
},

// Usage 3
todoRequest1: {
'loading, data'(newVal, oldVal) {}
},

// Usage 4
'todoRequest1, todoRequest2': {
'loading, data'(newVal, oldVal) {}
}
})
};

Batch watching also supports watching object.

Function description

mapAlovaHook

mapAlovaHook is used to map the state and function collection returned by alova's use hook to the vue component instance through mixins. It receives a callback function and returns the return value collection of use hook.

It is worth noting that the callback function will be executed in the created phase, and you can access the vue component instance in the following way.

// 1. Access the component instance through this. Note that the callback function cannot be an arrow function.
mapAlovaHook(function () {
console.log(this);
return {
todoRequest: useRequest(getData)
};
});

// =======================
// 2. Access the component instance through function parameters. In this case, arrow functions can be used
mapAlovaHook(vm => {
console.log(vm);
return {
todoRequest: useRequest(getData)
};
});

mapWatcher

mapWatcher is an helper function used to quickly define the watching handlers of hook states. It receives an object whose key is the key of the hook state or a string representation of the nested value, and whose value is the watching handler or watching object.

mapWatcher({
'todoRequest.loading'(newVal, oldVal) {
//...
},
todoRequest: {
data(newVal, oldVal) {
//...
}
},
todoRequest: {
'loading, data'(newVal, oldVal) {
//...
}
}
}

In addition to supporting watching assistance for alova useHook, mapWatcher can also be used to batch set watching handlers of custom states.

export default {
data() {
state1: '',
state2: 0
},

// pass false at the second parameter to watch the custom states
watch: mapWatcher({
'state1, state2'(newVal, oldVal) {
//...
}
}, false)
}

Type support

Automatic inference

@alova/vue-options provides complete ts type support. Whether using typescript or not, the mapped value type will be automatically inferred, for example:

this.todoRequest.loading; // boolean
this.todoRequest.error; // Error | undefined
this.todoRequest.data; // any
this.todoRequest$send; // (...args: any[]) => Promise<any>
this.todoRequest$onSuccess; // (handler: SuccessHandler) => void
this.todoRequest$onError; // (handler: ErrorHandler) => void
this.todoRequest$onComplete; // (handler: CompleteHandler) => void
// ...

Add types for response data

Except for this.todoRequest.data, all other values have the correct type, so how to set the type for data too? In fact, it is the same as alova used in other environments.

javascript

In javascript, you can use type annotations to add types. The first two generic parameters of Method are unknown, and the third generic parameter is the type of response data.

import { Method } from 'alova';

/** @type {() => Method<unknown, unknown, { content: string, time: string }[]>} */
export const getData = () => alovaInst.Get('/todolist');

typescript

To add response data type in typescript, please read alova documentation typescript chapter

limit

  1. Manage extra states is not supported yet.
  2. Currently, only alova’s three core useHooks of useRequest/useWatcher/useFetcher are supported, as well as the encapsulation based on the core useHook in your own project. @alova/scene is not supported yet. extension useHook.