diff --git a/src/mixin.ts b/src/mixin.ts index 078c846c..3dc3b191 100644 --- a/src/mixin.ts +++ b/src/mixin.ts @@ -149,7 +149,8 @@ export function mixin(Vue: VueConstructor) { } } - function customReactive(target: object) { + function customReactive(target: object, visited = new Set()) { + if (visited.has(target)) return if ( !isPlainObject(target) || isRef(target) || @@ -165,7 +166,8 @@ export function mixin(Vue: VueConstructor) { const val = target[k] defineReactive(target, k, val) if (val) { - customReactive(val) + visited.add(val) + customReactive(val, visited) } return }) diff --git a/test/setupContext.spec.ts b/test/setupContext.spec.ts index cb602031..6ec978f7 100644 --- a/test/setupContext.spec.ts +++ b/test/setupContext.spec.ts @@ -5,9 +5,12 @@ import { ref, nextTick, SetupContext, + getCurrentInstance, } from '../src' +import { mockWarn } from './helpers' describe('setupContext', () => { + mockWarn(true) it('should have proper properties', () => { let context: SetupContext = undefined! @@ -195,4 +198,31 @@ describe('setupContext', () => { expect(_attrs.foo).toBe('bar2') }) + + // #563 + it('should not RangeError: Maximum call stack size exceeded', async () => { + createApp( + defineComponent({ + template: `
`, + setup() { + // @ts-expect-error + const app = getCurrentInstance().proxy + let mockNT: any = [] + mockNT.__ob__ = {} + const test = { + app, + mockNT, + } + return { + test, + } + }, + }) + ).mount() + + await nextTick() + expect( + `"RangeError: Maximum call stack size exceeded"` + ).not.toHaveBeenWarned() + }) })