diff --git a/src/reactivity/reactive.ts b/src/reactivity/reactive.ts index d08b7c5b..f7ddc8fa 100644 --- a/src/reactivity/reactive.ts +++ b/src/reactivity/reactive.ts @@ -135,7 +135,7 @@ export function observe(obj: T): T { /** * Mock __ob__ for object recursively */ -function mockReactivityDeep(obj: any, seen = new Set()) { +export function mockReactivityDeep(obj: any, seen = new Set()) { if (seen.has(obj)) return def(obj, '__ob__', mockObserver(obj)) diff --git a/src/reactivity/set.ts b/src/reactivity/set.ts index dfbd40f4..2270c9ec 100644 --- a/src/reactivity/set.ts +++ b/src/reactivity/set.ts @@ -1,7 +1,14 @@ import { AnyObject } from '../types/basic' import { getVueConstructor } from '../runtimeContext' -import { isArray, isPrimitive, isUndef, isValidArrayIndex } from '../utils' -import { defineAccessControl } from './reactive' +import { + isArray, + isPrimitive, + isUndef, + isValidArrayIndex, + isObject, + hasOwn, +} from '../utils' +import { defineAccessControl, mockReactivityDeep } from './reactive' /** * Set a property on an object. Adds the new property, triggers change @@ -49,6 +56,11 @@ export function set(target: AnyObject, key: any, val: T): T { // IMPORTANT: define access control before trigger watcher defineAccessControl(target, key, val) + // in SSR, there is no __ob__. Mock for reactivity check + if (isObject(target[key]) && !hasOwn(target[key], '__ob__')) { + mockReactivityDeep(target[key]) + } + ob.dep.notify() return val } diff --git a/test/ssr/ssrReactive.spec.ts b/test/ssr/ssrReactive.spec.ts index 90ec277a..432244be 100644 --- a/test/ssr/ssrReactive.spec.ts +++ b/test/ssr/ssrReactive.spec.ts @@ -145,4 +145,11 @@ describe('SSR Reactive', () => { `"RangeError: Maximum call stack size exceeded"` ).not.toHaveBeenWarned() }) + + it('should work on objects sets with set()', () => { + const state = ref({}) + set(state.value, 'a', {}) + + expect(isReactive(state.value.a)).toBe(true) + }) })