From fb371359bfe77b92efbf947b1853da1ae2668b78 Mon Sep 17 00:00:00 2001 From: Wenlu Wang Date: Tue, 8 Feb 2022 09:35:36 +0800 Subject: [PATCH] feat(useCached): new function (#1169) Co-authored-by: wangwenlu Co-authored-by: Anthony Fu --- packages/.test/index.ts | 1 + packages/.test/nextTick.ts | 5 +++ packages/core/index.ts | 1 + packages/core/useCached/demo.vue | 48 +++++++++++++++++++++++++++ packages/core/useCached/index.md | 35 +++++++++++++++++++ packages/core/useCached/index.test.ts | 46 +++++++++++++++++++++++++ packages/core/useCached/index.ts | 17 ++++++++++ 7 files changed, 153 insertions(+) create mode 100644 packages/.test/nextTick.ts create mode 100644 packages/core/useCached/demo.vue create mode 100644 packages/core/useCached/index.md create mode 100644 packages/core/useCached/index.test.ts create mode 100644 packages/core/useCached/index.ts diff --git a/packages/.test/index.ts b/packages/.test/index.ts index aac043895d90..564b097edfb8 100644 --- a/packages/.test/index.ts +++ b/packages/.test/index.ts @@ -1,3 +1,4 @@ export * from './mount' export * from './polyfillFetch' export * from './retry' +export * from './nextTick' diff --git a/packages/.test/nextTick.ts b/packages/.test/nextTick.ts new file mode 100644 index 000000000000..260eb023dd11 --- /dev/null +++ b/packages/.test/nextTick.ts @@ -0,0 +1,5 @@ +export const nextTwoTick = () => new Promise((resolve) => { + setTimeout(() => { + setTimeout(resolve) + }) +}) diff --git a/packages/core/index.ts b/packages/core/index.ts index d84f63e92702..8b5a049febf2 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -15,6 +15,7 @@ export * from './useBattery' export * from './useBreakpoints' export * from './useBroadcastChannel' export * from './useBrowserLocation' +export * from './useCached' export * from './useClamp' export * from './useClipboard' export * from './useColorMode' diff --git a/packages/core/useCached/demo.vue b/packages/core/useCached/demo.vue new file mode 100644 index 000000000000..3afa981c13c1 --- /dev/null +++ b/packages/core/useCached/demo.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/core/useCached/index.md b/packages/core/useCached/index.md new file mode 100644 index 000000000000..c99fe985e04b --- /dev/null +++ b/packages/core/useCached/index.md @@ -0,0 +1,35 @@ +--- +category: Utilities +--- + +# useCached + +Cache a ref with a custom comparator. + +## Usage + +```ts +import { useCached } from '@vueuse/core' + +interface Data { + value: number + extra: number +} + +const source = ref({ value: 42, extra: 0 }) +const cached = useCached(value, (a, b) => a.value === b.value) + +source.value = { + value: 42, + extra: 1 +} + +console.log(cached.value) // { value: 42, extra: 0 } + +source.value = { + value: 43, + extra: 1 +} + +console.log(cached.value) // { value: 43, extra: 1 } +``` diff --git a/packages/core/useCached/index.test.ts b/packages/core/useCached/index.test.ts new file mode 100644 index 000000000000..cd9f09153e77 --- /dev/null +++ b/packages/core/useCached/index.test.ts @@ -0,0 +1,46 @@ +import { ref } from 'vue-demi' +import { nextTwoTick } from '../../.test' +import { useCached } from '.' + +function arrayEquals(a: T[], b: T[]): boolean { + if (a.length !== b.length) + return false + + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) + return false + } + return true +} + +describe('useCached', () => { + it('should be defined', () => { + expect(useCached).toBeDefined() + }) + + it('should work', async() => { + const arrayRef = ref([1]) + const initialArrayValue = arrayRef.value + + const cachedArrayRef = useCached(arrayRef, arrayEquals) + await nextTwoTick() + + expect(cachedArrayRef.value).toBe(initialArrayValue) + + arrayRef.value = initialArrayValue + await nextTwoTick() + + expect(cachedArrayRef.value).toBe(initialArrayValue) + + arrayRef.value = [1] + await nextTwoTick() + + expect(cachedArrayRef.value).toBe(initialArrayValue) + + arrayRef.value = [2] + await nextTwoTick() + + expect(cachedArrayRef.value).not.toBe(initialArrayValue) + expect(cachedArrayRef.value).toEqual([2]) + }) +}) diff --git a/packages/core/useCached/index.ts b/packages/core/useCached/index.ts new file mode 100644 index 000000000000..ec3fa87b4550 --- /dev/null +++ b/packages/core/useCached/index.ts @@ -0,0 +1,17 @@ +import type { Ref, WatchOptions } from 'vue-demi' +import { ref, watch } from 'vue-demi' + +export function useCached( + refValue: Ref, + comparator: (a: T, b: T) => boolean = (a, b) => a === b, + watchOptions?: WatchOptions, +): Ref { + const cachedValue = ref(refValue.value) as Ref + + watch(() => refValue.value, (value) => { + if (!comparator(value, cachedValue.value)) + cachedValue.value = value + }, watchOptions) + + return cachedValue +}