From d6b81d0c7134e7499d633b8c96e9c319f413d51f Mon Sep 17 00:00:00 2001 From: nighca Date: Tue, 19 Sep 2017 16:32:26 +0800 Subject: [PATCH] surpport fromMobx fields used in vue computed & watch --- src/install.ts | 32 ++++++++++++++++++++-------- test/index.ts | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/src/install.ts b/src/install.ts index b3461fa..6164c15 100644 --- a/src/install.ts +++ b/src/install.ts @@ -11,25 +11,27 @@ export default function install(Vue: typeof VueClass, mobxMethods: IMobxMethods) const defineReactive = (Vue as any).util.defineReactive + function beforeCreate(this: VueClass) { + const vm = this + getFromStoreEntries(vm).forEach(({ key, compute }) => { + defineReactive(vm, key, null) + }) + } + function created(this: VueClass) { const vm = this - const fromStore = vm.$options[optionName] - if (!fromStore) { + const entries = getFromStoreEntries(vm) + if (entries.length <= 0) { return } const disposers: Disposer[] = vm[disposersName] = [] - Object.keys(fromStore).forEach(key => { - const compute = fromStore[key] + entries.forEach(({ key, compute }) => { disposers.push(mobxMethods.reaction( () => compute.apply(vm), val => { - if (key in vm) { - vm[key] = val - } else { - defineReactive(vm, key, val) - } + vm[key] = val }, true )) @@ -47,7 +49,19 @@ export default function install(Vue: typeof VueClass, mobxMethods: IMobxMethods) } Vue.mixin({ + beforeCreate, created, beforeDestroy }) } + +function getFromStoreEntries(vm: VueClass) { + const fromStore = vm.$options[optionName] + if (!fromStore) { + return [] + } + + return Object.keys(fromStore).map( + key => ({ key, compute: fromStore[key] }) + ) +} diff --git a/test/index.ts b/test/index.ts index c4ef8b0..367f35d 100644 --- a/test/index.ts +++ b/test/index.ts @@ -94,6 +94,64 @@ test(`can use this.data in ${optionName}`, done => { }) }) + +test(`fields in ${optionName} can be used in watch & computed`, done => { + Vue.use(Movue, { reaction }) + + const data = observable({ + foo: 1 + }) + + const onFooChange = jest.fn() + const onFoobarChange = jest.fn() + + const vm = new Vue({ + data() { + return { + bar: 2 + } + }, + computed: { + foobar() { + return this.foo + this.bar + } + }, + [optionName]: { + foo() { + return data.foo + } + }, + watch: { + foo(value) { + onFooChange(value) + }, + foobar(value) { + onFoobarChange(value) + } + }, + render (h) { + const vm: any = this + return h('div', `${vm.foobar}`) + } + }).$mount() + + expect(vm.$el.textContent).toBe('3') + + vm.bar++ + runInAction(() => { + data.foo++ + }) + + nextTick(() => { + expect(vm.$el.textContent).toBe('5') + expect(onFooChange.mock.calls).toHaveLength(1) + expect(onFooChange.mock.calls[0][0]).toBe(2) + expect(onFoobarChange.mock.calls).toHaveLength(1) + expect(onFoobarChange.mock.calls[0][0]).toBe(5) + done() + }) +}) + class Counter { @observable num = 0 @computed get numPlus() {