Skip to content

Commit

Permalink
feat: add useDebounce
Browse files Browse the repository at this point in the history
  • Loading branch information
lmhcoding committed Sep 21, 2020
1 parent 23a142c commit 6a23363
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export * from './useHash'
export * from './useHistory'
export * from './useTimeout'
export * from './useTimeoutFn'
export * from './useDebounce'
29 changes: 29 additions & 0 deletions src/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { customRef, getCurrentInstance, onUnmounted } from 'vue'

export function useDebounce<T>(value: T, delay = 200) {
let timer: any
const clear = () => {
if (timer) {
clearTimeout(timer)
}
}
if (getCurrentInstance()) {
onUnmounted(() => {
clear()
})
}
return customRef((tracker, trigger) => ({
get() {
tracker()
return value
},
set(val: T) {
clear()
timer = setTimeout(() => {
value = val
timer = null
trigger()
}, delay)
}
}))
}
53 changes: 53 additions & 0 deletions tests/useDebounce.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useDebounce } from '../src/useDebounce'
import invokeHook from './util/invokeHook'

beforeEach(() => {
jest.useFakeTimers()
})

afterEach(() => {
jest.useRealTimers()
jest.clearAllMocks()
})

test('initial debounceValue should be equal to the params value', () => {
const debounceValue = useDebounce(4)
expect(debounceValue.value).toBe(4)
})

test('setTimeout should be called with default delay when debounceValue changed', () => {
const debounceValue = useDebounce(4)
debounceValue.value = 5
expect(setTimeout).toHaveBeenCalledTimes(1)
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 200)
})

test('debounceValue should changed when setTimeout callback was invoked', () => {
const debounceValue = useDebounce(4)
debounceValue.value = 5
expect(setTimeout).toHaveBeenCalledTimes(1)
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 200)
jest.advanceTimersByTime(200)
expect(debounceValue.value).toBe(5)
})

test('timer will be cleared and recrated when updating debounceValue less than 200s', () => {
const debounceValue = useDebounce(4)
debounceValue.value = 5
debounceValue.value = 6
expect(debounceValue.value).toBe(4)
expect(clearTimeout).toHaveBeenCalledTimes(1)
expect(setTimeout).toHaveBeenCalledTimes(2)
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 200)
jest.advanceTimersByTime(200)
expect(debounceValue.value).toBe(6)
})

test('timer should be cleared when component is unmounted and timer is not null', () => {
const wrapper = invokeHook(() => {
const debounceValue = useDebounce(4)
debounceValue.value = 5
})
wrapper.unmount()
expect(clearTimeout).toHaveBeenCalledTimes(1)
})

0 comments on commit 6a23363

Please sign in to comment.