Skip to content

Commit

Permalink
fix(toRefs): don't trigger unwanted watchEffects (#3260)
Browse files Browse the repository at this point in the history
  • Loading branch information
wvffle committed Jul 30, 2023
1 parent d3f7e6a commit 5309c26
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 11 deletions.
40 changes: 39 additions & 1 deletion packages/shared/toRefs/index.test.ts
@@ -1,4 +1,4 @@
import { computed, isVue3, reactive, ref } from 'vue-demi'
import { computed, isVue3, reactive, ref, watchSyncEffect } from 'vue-demi'
import { describe, expect, it, vi } from 'vitest'
import { toRefs } from '.'

Expand Down Expand Up @@ -98,6 +98,44 @@ describe('toRefs', () => {
expect(spy).toHaveBeenLastCalledWith(['a', 1])
})

it('should trigger unwanted effects with replaceRef = false', () => {
const spy = vi.fn()
const obj = ref({
a: 'a',
b: 0,
})

const { a, b } = toRefs(obj, { replaceRef: true })
expect(a.value).toBe('a')
expect(b.value).toBe(0)

watchSyncEffect(() => spy(a.value))

expect(spy).toHaveBeenCalledTimes(1)

b.value = 1
expect(spy).toHaveBeenCalledTimes(2)
})

it('should not trigger unwanted effects with replaceRef = false', () => {
const spy = vi.fn()
const obj = ref({
a: 'a',
b: 0,
})

const { a, b } = toRefs(obj, { replaceRef: false })
expect(a.value).toBe('a')
expect(b.value).toBe(0)

watchSyncEffect(() => spy(a.value))

expect(spy).toHaveBeenCalledTimes(1)

b.value = 1
expect(spy).toHaveBeenCalledTimes(1)
})

it('should save instance of class', () => {
class SomeClass {
v = 1
Expand Down
38 changes: 28 additions & 10 deletions packages/shared/toRefs/index.ts
@@ -1,6 +1,16 @@
import type { ToRefs } from 'vue-demi'
import { toRefs as _toRefs, customRef, isRef } from 'vue-demi'
import type { MaybeRef } from '../utils'
import { toValue } from '../toValue'
import type { MaybeRef, MaybeRefOrGetter } from '../utils'

export interface ToRefsOptions {
/**
* Replace the original ref with a copy on property update.
*
* @default true
*/
replaceRef?: MaybeRefOrGetter<boolean>
}

/**
* Extended `toRefs` that also accepts refs of an object.
Expand All @@ -10,6 +20,7 @@ import type { MaybeRef } from '../utils'
*/
export function toRefs<T extends object>(
objectRef: MaybeRef<T>,
options: ToRefsOptions = {},
): ToRefs<T> {
if (!isRef(objectRef))
return _toRefs(objectRef)
Expand All @@ -24,17 +35,24 @@ export function toRefs<T extends object>(
return objectRef.value[key]
},
set(v) {
if (Array.isArray(objectRef.value)) {
const copy: any = [...objectRef.value]
copy[key] = v
objectRef.value = copy
}
else {
const newObject = { ...objectRef.value, [key]: v }
const replaceRef = toValue(options.replaceRef) ?? true

Object.setPrototypeOf(newObject, Object.getPrototypeOf(objectRef.value))
if (replaceRef) {
if (Array.isArray(objectRef.value)) {
const copy: any = [...objectRef.value]
copy[key] = v
objectRef.value = copy
}
else {
const newObject = { ...objectRef.value, [key]: v }

objectRef.value = newObject
Object.setPrototypeOf(newObject, Object.getPrototypeOf(objectRef.value))

objectRef.value = newObject
}
}
else {
objectRef.value[key] = v
}
},
}))
Expand Down

0 comments on commit 5309c26

Please sign in to comment.