Browse Source

refactor(gui-v2): use `useCounter` to count running requests

pull/2877/head
braks 2 years ago
parent
commit
c39710b1fa
  1. 59
      packages/nc-gui-v2/composables/useApi/index.ts
  2. 2
      packages/nc-gui-v2/composables/useGlobal/getters.ts
  3. 4
      packages/nc-gui-v2/composables/useGlobal/state.ts
  4. 3
      packages/nc-gui-v2/composables/useGlobal/types.ts

59
packages/nc-gui-v2/composables/useApi/index.ts

@ -3,7 +3,7 @@ import { Api } from 'nocodb-sdk'
import type { Ref } from 'vue'
import type { EventHook, MaybeRef } from '@vueuse/core'
import { addAxiosInterceptors } from './interceptors'
import { createEventHook, ref, unref, useGlobal } from '#imports'
import { createEventHook, ref, unref, useCounter, useGlobal } from '#imports'
interface UseApiReturn<D = any, R = any> {
api: Api<any>
@ -52,30 +52,57 @@ interface UseApiProps<D = any> {
export function useApi<Data = any, RequestConfig = any>(props: UseApiProps<Data> = {}): UseApiReturn<Data, RequestConfig> {
const state = useGlobal()
/**
* Local state of running requests, do not confuse with global state of running requests
* This state is only counting requests made by this instance of `useApi` and not by other instances.
*/
const { count, inc, dec } = useCounter(0)
/** is request loading */
const isLoading = ref(false)
/** latest request error */
const error = ref(null)
const response = ref<any>(null)
/** latest request response */
const response = ref<unknown | null>(null)
const errorHook = createEventHook<AxiosError<Data, RequestConfig>>()
const responseHook = createEventHook<AxiosResponse<Data, RequestConfig>>()
/** fresh api instance - with interceptors for token refresh already bound */
const api = createApiInstance(props.apiOptions)
/** increment local and global request counter */
function addRequest() {
state.runningRequests.value.push(state.runningRequests.value.length + 1)
inc()
state.runningRequests.inc()
}
/** decrement local and global request counter */
function removeRequest() {
state.runningRequests.value.pop()
dec()
state.runningRequests.dec()
}
/** set loading state to false *only* if no request is still running */
function stopLoading() {
if (count.value === 0) {
isLoading.value = false
}
}
/** reset response and error refs */
function reset() {
error.value = null
response.value = null
}
api.instance.interceptors.request.use(
(config) => {
error.value = null
response.value = null
reset()
isLoading.value = true
addRequest()
@ -88,8 +115,10 @@ export function useApi<Data = any, RequestConfig = any>(props: UseApiProps<Data>
(requestError) => {
errorHook.trigger(requestError)
error.value = requestError
response.value = null
isLoading.value = false
stopLoading()
removeRequest()
@ -100,9 +129,9 @@ export function useApi<Data = any, RequestConfig = any>(props: UseApiProps<Data>
api.instance.interceptors.response.use(
(apiResponse) => {
responseHook.trigger(apiResponse as AxiosResponse<Data, RequestConfig>)
// can't properly typecast
response.value = apiResponse
isLoading.value = false
stopLoading()
removeRequest()
@ -111,7 +140,8 @@ export function useApi<Data = any, RequestConfig = any>(props: UseApiProps<Data>
(apiError) => {
errorHook.trigger(apiError)
error.value = apiError
isLoading.value = false
stopLoading()
removeRequest()
@ -119,5 +149,12 @@ export function useApi<Data = any, RequestConfig = any>(props: UseApiProps<Data>
},
)
return { api, isLoading, response, error, onError: errorHook.on, onResponse: responseHook.on }
return {
api,
isLoading,
response: response as Ref<AxiosResponse<Data, RequestConfig>>,
error,
onError: errorHook.on,
onResponse: responseHook.on,
}
}

2
packages/nc-gui-v2/composables/useGlobal/getters.ts

@ -17,7 +17,7 @@ export function useGlobalGetters(state: State): Getters {
/** global loading state */
let loading = $ref(false)
const isLoading = computed({
get: () => state.runningRequests.value.length > 0 || loading,
get: () => state.runningRequests.count.value > 0 || loading,
set: (_loading) => (loading = !_loading),
})

4
packages/nc-gui-v2/composables/useGlobal/state.ts

@ -2,7 +2,7 @@ import { usePreferredLanguages, useStorage } from '@vueuse/core'
import { useJwt } from '@vueuse/integrations/useJwt'
import type { JwtPayload } from 'jwt-decode'
import type { State, StoredState } from './types'
import { computed, ref, toRefs, useNuxtApp, useTimestamp } from '#imports'
import { computed, ref, toRefs, useCounter, useNuxtApp, useTimestamp } from '#imports'
import type { User } from '~/lib'
export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
@ -67,7 +67,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
const sidebarOpen = ref(false)
/** currently running requests */
const runningRequests = ref<number[]>([])
const runningRequests = useCounter()
/** global error */
const error = ref()

3
packages/nc-gui-v2/composables/useGlobal/types.ts

@ -2,6 +2,7 @@ import type { ComputedRef, Ref, ToRefs } from 'vue'
import type { WritableComputedRef } from '@vue/reactivity'
import type { JwtPayload } from 'jwt-decode'
import type { User } from '~/lib'
import type { useCounter } from '#imports'
export interface StoredState {
token: string | null
@ -16,7 +17,7 @@ export type State = ToRefs<Omit<StoredState, 'token'>> & {
jwtPayload: ComputedRef<(JwtPayload & User) | null>
sidebarOpen: Ref<boolean>
timestamp: Ref<number>
runningRequests: Ref<number[]>
runningRequests: ReturnType<typeof useCounter>
error: Ref<any>
}

Loading…
Cancel
Save