From debd37deefdd1c25bb829d5067a97f738f35516a Mon Sep 17 00:00:00 2001 From: ygj6 Date: Fri, 2 Jul 2021 16:19:04 +0800 Subject: [PATCH] fix(observe): solve the Ref not unwrapping on the ssr side issue with recursive way. (#723) Co-authored-by: Anthony Fu --- src/reactivity/reactive.ts | 28 +++++++++++++++++++++++++--- src/reactivity/set.ts | 3 +-- test/ssr/ssrReactive.spec.ts | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/reactivity/reactive.ts b/src/reactivity/reactive.ts index 5fbf8fe7..30ab9a05 100644 --- a/src/reactivity/reactive.ts +++ b/src/reactivity/reactive.ts @@ -127,14 +127,32 @@ export function observe(obj: T): T { // in SSR, there is no __ob__. Mock for reactivity check if (!hasOwn(observed, '__ob__')) { - def(observed, '__ob__', mockObserver(observed)) + mockReactivityDeep(observed) } return observed } -export function createObserver() { - return observe({}).__ob__ +/** + * Mock __ob__ for object recursively + */ +function mockReactivityDeep(obj: any, seen = new WeakMap()) { + if (seen.has(obj)) return + + def(obj, '__ob__', mockObserver(obj)) + seen.set(obj, true) + + for (const key of Object.keys(obj)) { + const value = obj[key] + if ( + !(isPlainObject(value) || isArray(value)) || + isRaw(value) || + !Object.isExtensible(value) + ) { + continue + } + mockReactivityDeep(value) + } } function mockObserver(value: any = {}): any { @@ -149,6 +167,10 @@ function mockObserver(value: any = {}): any { } } +export function createObserver() { + return observe({}).__ob__ +} + export function shallowReactive(obj: T): T export function shallowReactive(obj: any): any { if (!isObject(obj)) { diff --git a/src/reactivity/set.ts b/src/reactivity/set.ts index d1baecf2..02568bc1 100644 --- a/src/reactivity/set.ts +++ b/src/reactivity/set.ts @@ -41,8 +41,7 @@ export function set(target: AnyObject, key: any, val: T): T { return val } if (!ob) { - // If we are using `set` we can assume that the unwrapping is intended - defineAccessControl(target, key, val) + target[key] = val return val } defineReactive(ob.value, key, val) diff --git a/test/ssr/ssrReactive.spec.ts b/test/ssr/ssrReactive.spec.ts index b4325fa3..fd329827 100644 --- a/test/ssr/ssrReactive.spec.ts +++ b/test/ssr/ssrReactive.spec.ts @@ -102,4 +102,20 @@ describe('SSR Reactive', () => { new: true, }) }) + + // #721 + it('should behave correctly for the nested ref in the object', () => { + const state = { old: ref(false) } + set(state, 'new', ref(true)) + expect(JSON.stringify(state)).toBe( + '{"old":{"value":false},"new":{"value":true}}' + ) + }) + + // #721 + it('should behave correctly for ref of object', () => { + const state = ref({ old: ref(false) }) + set(state.value, 'new', ref(true)) + expect(JSON.stringify(state.value)).toBe('{"old":false,"new":true}') + }) })