From 765a56d17cbb7330c351bbb7951fbc35b4f3843d Mon Sep 17 00:00:00 2001 From: ygj6 Date: Sat, 5 Jun 2021 11:44:14 +0800 Subject: [PATCH 1/2] fix(observe): recursively solve the ref not unwrapping on the ssr side --- src/reactivity/reactive.ts | 19 +++++++++++++++++++ src/reactivity/set.ts | 3 +-- test/ssr/ssrReactive.spec.ts | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/reactivity/reactive.ts b/src/reactivity/reactive.ts index 38469e2e..034e6450 100644 --- a/src/reactivity/reactive.ts +++ b/src/reactivity/reactive.ts @@ -118,11 +118,30 @@ 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)) + walk(observed) } return observed } +/** + * Recursive obj, add __ob__ + */ +function walk(obj: any) { + var keys = Object.keys(obj) + for (let i = 0; i < keys.length; i++) { + if ( + !(isPlainObject(obj[keys[i]]) || isArray(obj[keys[i]])) || + isRaw(obj[keys[i]]) || + !Object.isExtensible(obj[keys[i]]) + ) { + continue + } + def(obj[keys[i]], '__ob__', mockObserver(obj[keys[i]])) + walk(obj[keys[i]]) + } +} + export function createObserver() { return observe({}).__ob__ } diff --git a/src/reactivity/set.ts b/src/reactivity/set.ts index 669487cf..ee658f8a 100644 --- a/src/reactivity/set.ts +++ b/src/reactivity/set.ts @@ -40,8 +40,7 @@ export function set(target: any, 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}') + }) }) From b070efaea0d422c48d8ce3fe16e17fcdff236a43 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 2 Jul 2021 16:12:26 +0800 Subject: [PATCH 2/2] chore: update --- src/reactivity/reactive.ts | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/reactivity/reactive.ts b/src/reactivity/reactive.ts index 034e6450..4769d16f 100644 --- a/src/reactivity/reactive.ts +++ b/src/reactivity/reactive.ts @@ -117,35 +117,34 @@ 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)) - walk(observed) + mockReactivityDeep(observed) } return observed } /** - * Recursive obj, add __ob__ + * Mock __ob__ for object recursively */ -function walk(obj: any) { - var keys = Object.keys(obj) - for (let i = 0; i < keys.length; i++) { +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(obj[keys[i]]) || isArray(obj[keys[i]])) || - isRaw(obj[keys[i]]) || - !Object.isExtensible(obj[keys[i]]) + !(isPlainObject(value) || isArray(value)) || + isRaw(value) || + !Object.isExtensible(value) ) { continue } - def(obj[keys[i]], '__ob__', mockObserver(obj[keys[i]])) - walk(obj[keys[i]]) + mockReactivityDeep(value) } } -export function createObserver() { - return observe({}).__ob__ -} - function mockObserver(value: any = {}): any { return { value, @@ -158,6 +157,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)) {