Skip to content

Commit

Permalink
fix(*): update useDebounce to fix delays in KTable after clearing the…
Browse files Browse the repository at this point in the history
… search
  • Loading branch information
sumimakito committed Mar 16, 2023
1 parent 6bed2bf commit fc9f48a
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 44 deletions.
4 changes: 3 additions & 1 deletion src/components/KCatalog/KCatalog.vue
Expand Up @@ -486,7 +486,9 @@ export default defineComponent({
hasInitialized.value = true
}
const { query, search } = useDebounce('', 350)
const query = ref('')
const [search] = useDebounce((q: string) => { query.value = q })
const { revalidate } = useRequest(
() => catalogFetcherCacheKey.value,
() => fetchData(),
Expand Down
30 changes: 23 additions & 7 deletions src/components/KTable/KTable.vue
Expand Up @@ -736,12 +736,20 @@ export default defineComponent({
return `k-table_${Math.floor(Math.random() * 1000)}_${props.fetcherCacheKey}` as string
})
const { query, search } = useDebounce('', 350)
const { revalidate } = useRequest(
const query = ref('')
const [searchDebounced, debounceSearch] = useDebounce((q: string) => { query.value = q }, 350)
const searchImmediately = debounceSearch(0) // generate a debounced function with zero delay (immediate)
const { revalidate: _revalidate } = useRequest(
() => tableFetcherCacheKey.value,
() => fetchData(),
{ revalidateOnFocus: false },
{ revalidateOnFocus: false, revalidateDebounce: 0 },
)
const [revalidateDebounced, debounceRevalidate] = useDebounce(_revalidate, 500)
const revalidateImmediately = debounceRevalidate(0) // generate a debounced function with zero delay (immediate)
const sortClickHandler = (header: TableHeader) => {
const { key, useSortHandlerFn } = header
const prevKey = sortColumnKey.value + '' // avoid pass by ref
Expand Down Expand Up @@ -779,7 +787,7 @@ export default defineComponent({
defaultSorter(key, prevKey, sortColumnOrder.value, data.value)
}
} else if (props.paginationType !== 'offset') {
revalidate()
revalidateDebounced()
}
// Emit an event whenever one of the tablePreferences are updated
Expand Down Expand Up @@ -845,11 +853,19 @@ export default defineComponent({
}
watch(() => props.searchInput, (newValue) => {
search(newValue)
if (newValue === '') {
searchImmediately(newValue)
} else {
searchDebounced(newValue)
}
}, { immediate: true })
watch(() => [query.value, page.value, pageSize.value], () => {
revalidate()
watch(() => [query.value, page.value, pageSize.value], ([newQuery, , , oldQuery]) => {
if (newQuery === '' && newQuery !== oldQuery) {
revalidateImmediately()
} else {
revalidateDebounced()
}
}, { deep: true, immediate: true })
onMounted(() => {
Expand Down
107 changes: 71 additions & 36 deletions src/composables/useUtilities.ts
@@ -1,3 +1,5 @@
/** @format */

import { ref, Ref, computed, watchEffect } from 'vue'
import useSWRV, { IConfig } from 'swrv'
import { AxiosResponse, AxiosError } from 'axios'
Expand All @@ -14,20 +16,31 @@ const swrvState = {
}

export default function useUtilities() {
const useRequest = <Data = unknown, Error = { message: string }> (key: IKey, fn?: fetcherFn<AxiosResponse<Data>>, config?: IConfig) => {
const useSwrvFn = typeof useSWRV === 'function'
? useSWRV
: () => ({
data: {},
error: null,
isValidating: false,
mutate: () => ({}),
})

const { data: response, error, isValidating, mutate: revalidate } = useSwrvFn<
AxiosResponse<Data>,
AxiosError<Error>
>(key, fn, { revalidateDebounce: 500, dedupingInterval: 100, ...config })
const useRequest = <Data = unknown, Error = { message: string }>(
key: IKey,
fn?: fetcherFn<AxiosResponse<Data>>,
config?: IConfig,
) => {
const useSwrvFn =
typeof useSWRV === 'function'
? useSWRV
: () => ({
data: {},
error: null,
isValidating: false,
mutate: () => ({}),
})

const {
data: response,
error,
isValidating,
mutate: revalidate,
} = useSwrvFn<AxiosResponse<Data>, AxiosError<Error>>(key, fn, {
revalidateDebounce: 500,
dedupingInterval: 100,
...config,
})

const data = computed(() => {
// @ts-ignore
Expand All @@ -43,30 +56,44 @@ export default function useUtilities() {
}
}

const useDebounce = (initialQuery: string, delay = 300) => {
/**
* useDebounce accepts a function and a default delay.
* It returns a debounced function with the default delay and a debounced function
* wrapper which can be used to generate a debounced function with any delay.
* @param fn the function to wrap
* @param defaultDelay the default delay in milliseconds to use
* @returns a debounced function with default delay and a debounced function wrapper
*/
const useDebounce = <F extends (...args: any[]) => any>(
fn: F,
defaultDelay = 300,
): [(...args: Parameters<F>) => void, (delay: number) => (...args: Parameters<F>) => void] => {
let timeout: any
const query = ref(initialQuery)

function search(q: string) {
clearTimeout(timeout)
timeout = setTimeout(() => {
query.value = q
}, delay)
}
const wrapDebouncedWithDelay =
(delay: number) =>
(...args: Parameters<F>) => {
clearTimeout(timeout)
if (delay > 0) {
timeout = setTimeout(() => {
fn(...args)
}, delay)
} else {
timeout = undefined
fn(...args)
}
}

return {
query,
search,
}
return [wrapDebouncedWithDelay(defaultDelay), wrapDebouncedWithDelay]
}

/**
* @param {String} key - the current key to sort by
* @param {String} previousKey - the previous key used to sort by
* @param {String} sortOrder - either ascending or descending
* @param {Array} items - the list of items to sort
* @return {Object} an object containing the previousKey and sortOrder
*/
* @param {String} key - the current key to sort by
* @param {String} previousKey - the previous key used to sort by
* @param {String} sortOrder - either ascending or descending
* @param {Array} items - the list of items to sort
* @return {Object} an object containing the previousKey and sortOrder
*/
const clientSideSorter = (key: string, previousKey: string, sortOrder: string, items: []) => {
let comparator = null

Expand Down Expand Up @@ -130,9 +157,11 @@ export default function useUtilities() {

watchEffect(() => {
const hasData =
response.value?.data?.length ||
response.value?.data?.data?.length ||
(!response.value?.data?.data && typeof response.value?.data === 'object' && Object.keys(response.value?.data).length)
response.value?.data?.length ||
response.value?.data?.data?.length ||
(!response.value?.data?.data &&
typeof response.value?.data === 'object' &&
Object.keys(response.value?.data).length)

if (response.value && hasData && isValidating.value) {
state.value = swrvState.VALIDATING_HAS_DATA
Expand Down Expand Up @@ -187,7 +216,13 @@ export default function useUtilities() {
* @returns A string to be used for the height of an element.
*/
const getSizeFromString = (sizeStr: string): string => {
return sizeStr === 'auto' || sizeStr.endsWith('%') || sizeStr.endsWith('vw') || sizeStr.endsWith('vh') || sizeStr.endsWith('px') ? sizeStr : sizeStr + 'px'
return sizeStr === 'auto' ||
sizeStr.endsWith('%') ||
sizeStr.endsWith('vw') ||
sizeStr.endsWith('vh') ||
sizeStr.endsWith('px')
? sizeStr
: sizeStr + 'px'
}

/**
Expand Down

0 comments on commit fc9f48a

Please sign in to comment.