Skip to content

Commit

Permalink
feat(watchAtMost): new function (vitest-dev#764)
Browse files Browse the repository at this point in the history
Co-authored-by: webfansplz <>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
webfansplz and antfu committed Sep 17, 2021
1 parent bc6c342 commit 7c4fefc
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module.exports = {
paths: ['vue', '@vue/composition-api'],
},
],
'node/no-callback-literal': 'off',
},
overrides: [
{
Expand Down
7 changes: 7 additions & 0 deletions indexes.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,13 @@
"package": "shared",
"internal": true
},
{
"name": "watchAtMost",
"package": "shared",
"docs": "https://vueuse.org/shared/watchAtMost/",
"category": "Watch",
"description": "`watch` with the number of times triggered"
},
{
"name": "watchWithFilter",
"package": "shared",
Expand Down
1 change: 1 addition & 0 deletions packages/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
- [`pausableWatch`](https://vueuse.org/shared/pausableWatch/) — pausable watch
- [`throttledWatch`](https://vueuse.org/shared/throttledWatch/) — throttled watch
- [`until`](https://vueuse.org/shared/until/) — promised one-time watch for changes
- [`watchAtMost`](https://vueuse.org/shared/watchAtMost/)`watch` with the number of times triggered
- [`watchWithFilter`](https://vueuse.org/shared/watchWithFilter/)`watch` with additional EventFilter control
- [`whenever`](https://vueuse.org/shared/whenever/) — shorthand for watching value to be truthy

Expand Down
1 change: 1 addition & 0 deletions packages/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ export * from './useTimeout'
export * from './useTimeoutFn'
export * from './useToggle'
export * from './utils'
export * from './watchAtMost'
export * from './watchWithFilter'
export * from './whenever'
23 changes: 23 additions & 0 deletions packages/shared/watchAtMost/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
category: Watch
---

# watchAtMost

`watch` with the number of times triggered.

## Usage

Similar to `watch` with an extra option `count` which set up the number of times the callback function is triggered. After the count is reached, the watch will be stopped automatically.

```ts
import { watchAtMost } from '@vueuse/core'

watchAtMost(
source,
() => { console.log('trigger!') }, // triggered it at most 3 times
{
count: 3, // the number of times triggered
}
)
```
21 changes: 21 additions & 0 deletions packages/shared/watchAtMost/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ref, nextTick } from 'vue-demi'
import { watchAtMost } from '.'

describe('watchAtMost', () => {
it('should work', async() => {
const num = ref(0)
const spy = jest.fn()

const { count } = watchAtMost(num, spy, {
count: 2,
})
num.value = 1
await nextTick()
num.value = 2
await nextTick()
num.value = 3
await nextTick()
expect(spy).toBeCalledTimes(2)
expect(count.value).toBe(2)
})
})
46 changes: 46 additions & 0 deletions packages/shared/watchAtMost/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Ref, WatchSource, ref, unref, WatchStopHandle, WatchCallback } from 'vue-demi'
import { MapOldSources, MapSources, MaybeRef } from '../utils'
import { WatchWithFilterOptions, watchWithFilter } from '../watchWithFilter'

export interface WatchAtMostOptions<Immediate> extends WatchWithFilterOptions<Immediate> {
count: MaybeRef<number>
}

export interface WatchAtMostReturn {
stop: WatchStopHandle
count: Ref<number>
}

// overlads
export function watchAtMost<T extends Readonly<WatchSource<unknown>[]>, Immediate extends Readonly<boolean> = false>(source: T, cb: WatchCallback<MapSources<T>, MapOldSources<T, Immediate>>, options: WatchAtMostOptions<Immediate>): WatchAtMostReturn

export function watchAtMost<T extends Readonly<WatchSource<unknown>[]>, Immediate extends Readonly<boolean> = false>(source: T, cb: WatchCallback<MapSources<T>, MapOldSources<T, Immediate>>, options: WatchAtMostOptions<Immediate>): WatchAtMostReturn

export function watchAtMost<T, Immediate extends Readonly<boolean> = false>(sources: WatchSource<T>, cb: WatchCallback<T, Immediate extends true ? T | undefined : T>, options: WatchAtMostOptions<Immediate>): WatchAtMostReturn

// implementation
export function watchAtMost<Immediate extends Readonly<boolean> = false>(
source: any,
cb: any,
options: WatchAtMostOptions<Immediate>,
): WatchAtMostReturn {
const {
count,
...watchOptions
} = options

const current = ref(0)

const stop = watchWithFilter(
source,
(...args) => {
current.value += 1
if (current.value >= unref(count))
stop()
cb(...args)
},
watchOptions,
)

return { count: current, stop }
}

0 comments on commit 7c4fefc

Please sign in to comment.