Skip to content

Commit

Permalink
feat: useArrayReduce
Browse files Browse the repository at this point in the history
  • Loading branch information
yjl9903 committed Jul 12, 2022
1 parent dea9961 commit 2433051
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
38 changes: 38 additions & 0 deletions packages/shared/useArrayReduce/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
category: Utilities
---

# useArrayReduce

Reactively array reduce.

## Usage

```js
import { useArrayReduce } from '@vueuse/core'

const sum = useArrayReduce([ref(1), ref(2), ref(3)], (sum, val) => sum + val)
// sum.value: 6
```

### Use with reactive array

```js
import { useArrayReduce } from '@vueuse/core'

const list = reactive([1, 2])
const sum = useArrayReduce(list, (sum, val) => sum + val)

list.push(3)
// sum.value: 6
```

### Use with initialValue

```js
import { useArrayReduce } from '@vueuse/core'

const list = reactive([{ num: 1 }, { num: 2 }])
const sum = useArrayReduce(list, (sum, val) => sum + val.num, 0)
// sum.value: 3
```
44 changes: 44 additions & 0 deletions packages/shared/useArrayReduce/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { reactive, ref } from 'vue-demi'
import { useSetup } from '../../.test'
import { useArrayReduce } from '../useArrayReduce'

describe('useArrayReduce', () => {
it('should be defined', () => {
expect(useArrayReduce).toBeDefined()
})

it('should calulate the array sum', () => {
useSetup(() => {
const item1 = ref(1)
const item2 = ref(2)
const sum = useArrayReduce([item1, item2, 3], (a, b) => a + b)
expect(sum.value).toBe(6)

item1.value = 4
expect(sum.value).toBe(9)

item2.value = 3
expect(sum.value).toBe(10)
})
})

it('should work with reactive array', () => {
useSetup(() => {
const list = reactive([1, 2])
const sum = useArrayReduce(list, (a, b) => a + b)
expect(sum.value).toBe(3)

list.push(3)
expect(sum.value).toBe(6)
})
})

it('should work with initialValue', () => {
const list = reactive([{ num: 1 }, { num: 2 }])
const sum = useArrayReduce(list, (sum, val) => sum + val.num, 0)
expect(sum.value).toBe(3)

list.push({ num: 3 })
expect(sum.value).toBe(6)
})
})
35 changes: 35 additions & 0 deletions packages/shared/useArrayReduce/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { MaybeComputedRef } from '@vueuse/shared'
import type { ComputedRef } from 'vue-demi'
import { resolveUnref } from '@vueuse/shared'
import { computed } from 'vue-demi'

export type UseArrayReducer<PV, CV, R> = (previousValue: PV, currentValue: CV, currentIndex: number) => R

export function useArrayReduce<T>(
list: MaybeComputedRef<MaybeComputedRef<T>[]>,
reducer: UseArrayReducer<T, T, T>,
): ComputedRef<T>

export function useArrayReduce<T, U>(
list: MaybeComputedRef<MaybeComputedRef<T>[]>,
reducer: UseArrayReducer<U, T, U>,
initialValue: U,
): ComputedRef<U>

export function useArrayReduce<T>(
list: MaybeComputedRef<MaybeComputedRef<T>[]>,
reducer: ((...p: any[]) => any),
...args: any[]
): ComputedRef<T> {
return computed(() => {
const reduce = Array.prototype.reduce.bind(resolveUnref(list))

const reduceCallback = (sum: any, value: any, index: number) => reducer(resolveUnref(sum), resolveUnref(value), index)

// Depending on the behavior of reduce, undefined is also a valid initialization value,
// and this code will distinguish the behavior between them.
return args.length
? reduce(reduceCallback, args[0])
: reduce(reduceCallback)
})
}

0 comments on commit 2433051

Please sign in to comment.