This gist provides a useAsyncComputed
function which allows to create asynchronous dependencies on reactive values (using Vue 3's Composition API).
Requires at least Vue 3.0 and TypeScript 4.0.
import { ref } from 'vue'
import useAsyncComputed from './use-async-computed'
const packageName = ref('color-blend')
function getDownloads() {
return fetch(`https://api.npmjs.org/downloads/point/last-week/${packageName.value}`)
.then(response => response.json())
.then(result => result.downloads)
}
const [downloads] = useAsyncComputed(getDownloads, 0)
Whenever packageName
is updated, the downloads
will stay the same until the returned computed promise resolves.
The second parameter passed to the useAsyncComputed
function is optional. If provided, it is used as the initial value held by the computed ref until its first evaluation resolves.
The return value of useAsyncComputed
is a two-item tuple. While the first item holds the ref containing the latest evaluation result, the second item is a boolean ref which tells whether the computed ref is currently being (re-)evaluated.
const [downloads, isGettingDownloads] = useAsyncComputed(getDownloads, 0)
This may be used for displaying a loading indicator instead of the stale downloads
value when the packageName
changes.
The asyny computed callback receives an onCancel
function as its first argument. It can be invoked with a callback which will be executed when a re-evaluation of the async computed value is triggered before the current has finished.
This can be used to clean up resources used for evaluation, e.g. we could cancel fetch
requests to the npm API by adjusting our getDownloads
function from the introductory example:
function getDownloads(onCancel) {
const abortController = new AbortController()
onCancel(() => {
abortController.abort()
})
return fetch(`https://api.npmjs.org/downloads/point/last-week/${packageName.value}`, {
signal: abortController.signal
})
.then(response => response.json())
.then(result => result.downloads)
}
-
Just like Vue's built-in
computed
function,useAsyncComputed
does dependency tracking and is automatically re-evaluated when dependencies change.Note however that only dependencies referenced in the first call stack are considered for this. In other words: Dependencies which are accessed asynchronously are not triggering re-evaluation of the async computed value.
-
As opposed to Vue's built-in
computed
function, re-evaluation of the async computed value is triggered whenever dependencies are changing, regardless whether its result is being used or not.
Had the same problem, computed properties in vue 3 are lazy and cached, and therefore great fit for async fetches. Sadly they do not support Promise returnsout of the box. Luckily there is a solution using vue's reactive components, so I created https://www.npmjs.com/package/vue3-async-computed plugin. Hope it helps. Usage is simple:
Here
profile
property depends onuserID
and it's asynchronously computed whenuserID
changes.