From bc9665d188dba45c4e9712e0436ae6ae2799c19f Mon Sep 17 00:00:00 2001 From: Mikhailov Nikita Date: Fri, 25 Aug 2023 19:31:59 +0300 Subject: [PATCH] fix(syncRef): avoid infinite sync (#3312) Co-authored-by: Anthony Fu --- packages/shared/syncRef/index.test.ts | 8 +++--- packages/shared/syncRef/index.ts | 35 +++++++++++++++++---------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/shared/syncRef/index.test.ts b/packages/shared/syncRef/index.test.ts index ad5d464f41e..b982630caed 100644 --- a/packages/shared/syncRef/index.test.ts +++ b/packages/shared/syncRef/index.test.ts @@ -51,18 +51,18 @@ 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) @@ -70,7 +70,7 @@ describe('syncRef', () => { right.value = 10 expect(right.value).toBe(10) - expect(left.value).toBe(5) + expect(left.value).toBe(3) }) it('works with only rtl convertor', () => { diff --git a/packages/shared/syncRef/index.ts b/packages/shared/syncRef/index.ts index 975c7126dde..c0fe3391bcc 100644 --- a/packages/shared/syncRef/index.ts +++ b/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 extends ConfigurableFlushSync { /** @@ -47,30 +48,38 @@ export function syncRef(left: Ref, right: Ref, 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 }