diff --git a/src/mixin.ts b/src/mixin.ts index 1a1a1805..9f21b093 100644 --- a/src/mixin.ts +++ b/src/mixin.ts @@ -5,7 +5,7 @@ import { SetupFunction, Data, } from './component' -import { isRef, isReactive, markRaw, markReactive } from './reactivity' +import { isRef, isReactive, markRaw, markReactive, toRefs } from './reactivity' import { isPlainObject, assert, proxy, warn, isFunction } from './utils' import { ref } from './apis' import vmStateManager from './utils/vmStateManager' @@ -94,13 +94,16 @@ export function mixin(Vue: VueConstructor) { return activateCurrentInstance(vm, () => bindingFunc()) } return - } - if (isPlainObject(binding)) { + } else if (isPlainObject(binding)) { + if (isReactive(binding)) { + binding = toRefs(binding) as Data + } + const bindingObj = binding vmStateManager.set(vm, 'rawBindings', binding) Object.keys(binding).forEach((name) => { - let bindingValue = bindingObj[name] + let bindingValue: any = bindingObj[name] // only make primitive value reactive if (!isRef(bindingValue)) { if (isReactive(bindingValue)) { diff --git a/test/helpers/utils.ts b/test/helpers/utils.ts index 8d8f5d54..ba4060d6 100644 --- a/test/helpers/utils.ts +++ b/test/helpers/utils.ts @@ -3,3 +3,7 @@ const Vue = require('vue/dist/vue.common.js') export function nextTick(): Promise { return Vue.nextTick() } + +export function sleep(ms = 100) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} diff --git a/test/setup.spec.js b/test/setup.spec.js index 075c231b..09a8bb75 100644 --- a/test/setup.spec.js +++ b/test/setup.spec.js @@ -9,7 +9,9 @@ const { toRefs, markRaw, toRaw, + nextTick, } = require('../src') +const { sleep } = require('./helpers/utils') describe('setup', () => { beforeEach(() => { @@ -861,4 +863,27 @@ describe('setup', () => { const vm = new Vue(Constructor).$mount() expect(vm.$el.textContent).toBe('Composition-api') }) + + // #487 + it('should handle updates for directly return a reactive object.', async () => { + const opts = { + template: '
{{ count }}
', + setup() { + const state = reactive({ count: 1 }) + + setTimeout(() => { + state.count = 2 + }, 1) + + return state + }, + } + const Constructor = Vue.extend(opts).extend({}) + + const vm = new Vue(Constructor).$mount() + expect(vm.$el.textContent).toBe('1') + await sleep(10) + await nextTick() + expect(vm.$el.textContent).toBe('2') + }) })