Skip to content

Instantly share code, notes, and snippets.

@jacekkarczmarczyk
Created August 21, 2020 20:08
Show Gist options
  • Save jacekkarczmarczyk/8bd17cb6fb6a19a5b6134b6c69c042e3 to your computer and use it in GitHub Desktop.
Save jacekkarczmarczyk/8bd17cb6fb6a19a5b6134b6c69c042e3 to your computer and use it in GitHub Desktop.
Async computed composable for Vue
// TODO debounce/throttle support
import { computed, ComputedRef, Ref, ref, watch } from '@vue/composition-api';
export function useAsyncComputed<R> (load: () => Promise<R>): {
error: ComputedRef<unknown>;
loading: ComputedRef<boolean>;
value: ComputedRef<R | undefined>;
forceRefresh: () => void;
};
export function useAsyncComputed<R> (load: () => Promise<R>, defaultValue: R): {
error: ComputedRef<unknown>;
loading: ComputedRef<boolean>;
value: ComputedRef<R>;
forceRefresh: () => void;
};
export function useAsyncComputed<R> (load: () => Promise<R>, defaultValue?: R) {
const requestId = ref(0);
const asyncValue = ref(defaultValue) as Ref<R | undefined>;
const loading = ref(false);
const error = ref<unknown>();
const effect = async (response: Promise<R>) => {
const currentRequestId = requestId.value;
try {
error.value = undefined;
loading.value = true;
const result = await response;
if (currentRequestId === requestId.value) {
asyncValue.value = result;
}
} catch (error) {
if (process.env.NODE_ENV === 'development') {
console.error(error);
}
if (currentRequestId === requestId.value) {
asyncValue.value = defaultValue;
error.value = error;
}
} finally {
if (currentRequestId === requestId.value) {
loading.value = false;
}
}
};
watch(() => requestId.value ? load() : null, promise => promise && effect(promise));
return {
error: computed(() => error.value),
loading: computed(() => loading.value),
value: computed(() => (requestId.value || ++requestId.value) && asyncValue.value),
forceRefresh: () => {
++requestId.value;
},
};
}
@jacekkarczmarczyk
Copy link
Author

jacekkarczmarczyk commented Aug 21, 2020

Normal sync computed

const search = ref('');
const results = computed<Item[]>(() => getSyncData(search.value));

watch + ref

const search = ref('');
const results = ref<Item[]>([]);
const loading = ref(false);
const error = ref();

watch(search, async newSearch => {
  try {
    loading.value = true;
    results.value = await getAsyncData(newSearch);
  } catch (e) {
    error.value = e;
  } finally {
    loading.value = false;
  }
});

useAsyncComputed

const search = ref('');
const { loading, error, value: results } = useAsyncComputed<Item[]>(() => getAsyncData(newSearch.value));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment