Skip to content

Commit

Permalink
feat(reactivePick): add predicate parameter (#2850)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alfred-Skyblue committed Mar 28, 2023
1 parent bbabdbd commit 0bde454
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 3 deletions.
19 changes: 18 additions & 1 deletion packages/shared/reactivePick/index.md
Expand Up @@ -8,7 +8,9 @@ Reactively pick fields from a reactive object.

## Usage

```js
### Basic Usage

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

const obj = reactive({
Expand All @@ -21,6 +23,21 @@ const obj = reactive({
const picked = reactivePick(obj, 'x', 'elementX') // { x: number, elementX: number }
```

### Predicate Usage

```ts
import { reactivePick } from '@vueuse/core'
const source = reactive({
foo: 'foo',
bar: 'bar',
baz: 'baz',
qux: true,
})
const state = reactivePick(source, (value, key) => key !== 'bar' && value !== true)
// { foo: string, baz: string }
source.qux = false
// { foo: string, baz: string, qux: boolean }
````
### Scenarios

#### Selectively passing props to child
Expand Down
37 changes: 37 additions & 0 deletions packages/shared/reactivePick/index.test.ts
Expand Up @@ -44,4 +44,41 @@ describe('reactivePick', () => {
bar: 'bar2',
})
})
it('should work with predicate', () => {
const source = reactive({
foo: 'foo',
bar: 'bar',
baz: 'baz',
qux: true,
})
const state = reactivePick(source, (value, key) => {
return key !== 'bar' && value !== true
})

expect(state).toEqual({
foo: 'foo',
baz: 'baz',
})

source.foo = 'foo2'

expect(state).toEqual({
foo: 'foo2',
baz: 'baz',
})

source.bar = 'bar1'

expect(state).toEqual({
foo: 'foo2',
baz: 'baz',
})

source.qux = false
expect(state).toEqual({
foo: 'foo2',
baz: 'baz',
qux: false,
})
})
})
18 changes: 16 additions & 2 deletions packages/shared/reactivePick/index.ts
@@ -1,5 +1,18 @@
import type { UnwrapRef } from 'vue-demi'
import { reactive, toRef } from 'vue-demi'
import { toRef, toRefs } from 'vue-demi'
import { reactiveComputed } from '../reactiveComputed'
import { resolveUnref } from '../resolveUnref'

export type ReactivePickPredicate<T> = (value: T[keyof T], key: keyof T) => boolean

export function reactivePick<T extends object, K extends keyof T>(
obj: T,
...keys: (K | K[])[]
): { [S in K]: UnwrapRef<T[S]> }
export function reactivePick<T extends object>(
obj: T,
predicate: ReactivePickPredicate<T>
): { [S in keyof T]?: UnwrapRef<T[S]> }

/**
* Reactively pick fields from a reactive object
Expand All @@ -11,5 +24,6 @@ export function reactivePick<T extends object, K extends keyof T>(
...keys: (K | K[])[]
): { [S in K]: UnwrapRef<T[S]> } {
const flatKeys = keys.flat() as K[]
return reactive(Object.fromEntries(flatKeys.map(k => [k, toRef(obj, k)]))) as any
const predicate = flatKeys[0] as unknown as ReactivePickPredicate<T>
return reactiveComputed(() => typeof predicate === 'function' ? Object.fromEntries(Object.entries(toRefs(obj)).filter(([k, v]) => predicate(resolveUnref(v) as T[K], k as K))) : Object.fromEntries(flatKeys.map(k => [k, toRef(obj, k)]))) as any
}

0 comments on commit 0bde454

Please sign in to comment.