From 29b294c2be1bdbb57d6341871df72848c9d0b034 Mon Sep 17 00:00:00 2001 From: pimlie Date: Mon, 3 May 2021 11:05:18 +0200 Subject: [PATCH] fix: apply diff on nested computed objects --- examples/vue-router/Child.js | 9 +++++-- src/object-merge/proxy.ts | 2 +- src/useApi.ts | 1 - src/utils/diff.ts | 3 +-- test/unit/use-api.test.ts | 48 ++++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 test/unit/use-api.test.ts diff --git a/examples/vue-router/Child.js b/examples/vue-router/Child.js index 41fe3fa..7a663c1 100644 --- a/examples/vue-router/Child.js +++ b/examples/vue-router/Child.js @@ -1,4 +1,4 @@ -import { defineComponent, reactive, computed, toRefs, onUnmounted } from 'vue' +import { defineComponent, ref, reactive, computed, toRefs, onUnmounted } from 'vue' import { useRoute } from 'vue-router' import { useMeta } from 'vue-meta' @@ -14,12 +14,14 @@ export default defineComponent({ metaUpdated }) + const ogTitle = ref('Og Child Title') + const metaConfig = computed(() => ({ charset: 'utf16', title: route.name[0].toUpperCase() + route.name.slice(1), description: 'Description ' + route.name, og: { - title: 'Og Title ' + route.name + title: ogTitle.value + ' ' + route.name } })) @@ -29,6 +31,9 @@ export default defineComponent({ onUnmounted(() => (metaUpdated = 'yes')) + setTimeout(() => (ogTitle.value = 'Updated Child Og Title'), 1000) + setTimeout(() => (delete metaConfig.value.og), 3000) + onRemoved(() => { console.log('Meta was removed', pageName.value) }) diff --git a/src/object-merge/proxy.ts b/src/object-merge/proxy.ts index 06623aa..676b836 100644 --- a/src/object-merge/proxy.ts +++ b/src/object-merge/proxy.ts @@ -51,7 +51,7 @@ export const createHandler = (context: MergeContext, resolveContext: Resol }, set: (target, key, value) => { const success = Reflect.set(target, key, value) - // console.warn(success, 'PROXY SET\nkey:', key, '\npath:', pathSegments, '\ntarget:', isArray(target), target, '\ncontext:\n', context) + // console.warn(success, 'PROXY SET\nkey:', key, '\nvalue:', value, '\npath:', pathSegments, '\ntarget:', isArray(target), target, '\ncontext:\n', context) if (success) { const isArrayItem = isArray(target) diff --git a/src/useApi.ts b/src/useApi.ts index 6660564..98e1e0a 100644 --- a/src/useApi.ts +++ b/src/useApi.ts @@ -29,7 +29,6 @@ export function useMeta (source: MetaSource, manager?: MetaManager): MetaProxy { if (isProxy(source)) { watch(source, (newSource, oldSource) => { - // We only care about first level props, second+ level will already be changed by the merge proxy applyDifference(metaProxy.meta, newSource, oldSource) }) diff --git a/src/utils/diff.ts b/src/utils/diff.ts index 99b5b4c..be22470 100644 --- a/src/utils/diff.ts +++ b/src/utils/diff.ts @@ -12,9 +12,8 @@ export function applyDifference (target: AnyObject, newSource: AnyObject, oldSou continue } - // We dont care about nested objects here , these changes - // should already have been tracked by the MergeProxy if (isObject(target[key])) { + applyDifference(target[key], newSource[key], oldSource[key]) continue } diff --git a/test/unit/use-api.test.ts b/test/unit/use-api.test.ts new file mode 100644 index 0000000..d10d214 --- /dev/null +++ b/test/unit/use-api.test.ts @@ -0,0 +1,48 @@ +import { defineComponent, ref, computed } from 'vue' +import { mount } from '@vue/test-utils' +import { createMetaManager, useMeta, useActiveMeta } from '../../src' + +describe('useMeta', () => { + test('Computed nested objects properties update the active metadata on change', async () => { + const component = defineComponent({ + setup () { + const title = ref('Title') + + useMeta(computed(() => ({ + title: title.value + }))) + + const metadata = useActiveMeta() + + return { + title, + metadata + } + }, + methods: { + updateTitle (title: string) { + this.title = title + } + }, + template: '
test
' + }) + + const wrapper = mount(component, { + global: { + plugins: [ + createMetaManager() + ] + } + }) + + expect(wrapper.vm.title).toBe('Title') + expect(wrapper.vm.metadata.title).toBe('Title') + + wrapper.vm.updateTitle('Updated Title') + expect(wrapper.vm.title).toBe('Updated Title') + expect(wrapper.vm.metadata.title).toBe('Title') + + await wrapper.vm.$nextTick() + expect(wrapper.vm.metadata.title).toBe('Updated Title') + }) +})