Skip to content

Commit

Permalink
fix(syncRef): avoid infinite sync (#3312)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
chaii3 and antfu committed Aug 25, 2023
1 parent 3420640 commit bc9665d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 17 deletions.
8 changes: 4 additions & 4 deletions packages/shared/syncRef/index.test.ts
Expand Up @@ -51,26 +51,26 @@ describe('syncRef', () => {

it('works with mutual convertors', () => {
const left = ref(10)
const right = ref(1)
const right = ref(2)

syncRef(left, right, {
transform: {
ltr: left => left * 2,
rtl: right => Math.round(right / 2),
rtl: right => Math.floor(right / 3),
},
})

// check immediately sync
expect(right.value).toBe(20)
expect(left.value).toBe(10)
expect(left.value).toBe(6)

left.value = 30
expect(right.value).toBe(60)
expect(left.value).toBe(30)

right.value = 10
expect(right.value).toBe(10)
expect(left.value).toBe(5)
expect(left.value).toBe(3)
})

it('works with only rtl convertor', () => {
Expand Down
35 changes: 22 additions & 13 deletions packages/shared/syncRef/index.ts
@@ -1,6 +1,7 @@
import type { Ref, WatchStopHandle } from 'vue-demi'
import { watch } from 'vue-demi'
import type { Ref } from 'vue-demi'
import type { ConfigurableFlushSync } from '../utils'
import type { WatchPausableReturn } from '../watchPausable'
import { pausableWatch } from '../watchPausable'

export interface SyncRefOptions<L, R = L> extends ConfigurableFlushSync {
/**
Expand Down Expand Up @@ -47,30 +48,38 @@ export function syncRef<L, R = L>(left: Ref<L>, right: Ref<R>, options: SyncRefO
transform = {},
} = options

let watchLeft: WatchStopHandle
let watchRight: WatchStopHandle
const watchers: WatchPausableReturn[] = []

const transformLTR = transform.ltr ?? (v => v)
const transformRTL = transform.rtl ?? (v => v)

if (direction === 'both' || direction === 'ltr') {
watchLeft = watch(
watchers.push(pausableWatch(
left,
newValue => right.value = transformLTR(newValue) as R,
(newValue) => {
watchers.forEach(w => w.pause())
right.value = transformLTR(newValue) as R
watchers.forEach(w => w.resume())
},
{ flush, deep, immediate },
)
))
}

if (direction === 'both' || direction === 'rtl') {
watchRight = watch(
watchers.push(pausableWatch(
right,
newValue => left.value = transformRTL(newValue) as L,
(newValue) => {
watchers.forEach(w => w.pause())
left.value = transformRTL(newValue) as L
watchers.forEach(w => w.resume())
},
{ flush, deep, immediate },
)
))
}

return () => {
watchLeft?.()
watchRight?.()
const stop = () => {
watchers.forEach(w => w.stop())
}

return stop
}

0 comments on commit bc9665d

Please sign in to comment.