Skip to content

Commit

Permalink
feat(useArrayReduce): new function (#1919)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
yjl9903 and antfu committed Jul 16, 2022
1 parent 5a05036 commit 79e4433
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 0 deletions.
38 changes: 38 additions & 0 deletions packages/shared/useArrayReduce/index.md
@@ -0,0 +1,38 @@
---
category: Array
---

# useArrayReduce

Reactive `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
@@ -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 calculate 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 as number)
expect(sum.value).toBe(3)

list.push({ num: 3 })
expect(sum.value).toBe(6)
})
})
39 changes: 39 additions & 0 deletions packages/shared/useArrayReduce/index.ts
@@ -0,0 +1,39 @@
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: MaybeComputedRef<U>,
): ComputedRef<U>

/**
* Reactive `Array.reduce`
*
* @see https://vueuse.org/useArrayReduce
*/
export function useArrayReduce<T>(
list: MaybeComputedRef<MaybeComputedRef<T>[]>,
reducer: ((...p: any[]) => any),
...args: any[]
): ComputedRef<T> {
const reduceCallback = (sum: any, value: any, index: number) => reducer(resolveUnref(sum), resolveUnref(value), index)

return computed(() => {
const resolved = resolveUnref(list)
// 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
? resolved.reduce(reduceCallback, resolveUnref(args[0]))
: resolved.reduce(reduceCallback)
})
}

0 comments on commit 79e4433

Please sign in to comment.