mobxjs / mobx-vue

🐉 Vue bindings for MobX
MIT License
476 stars 21 forks source link

Exception when using with mobx-state-tree #51

Open bestmazzo opened 4 years ago

bestmazzo commented 4 years ago

Hello, I'm facing a strange exception, and I was able to reproduce it in the tests below. I'm writing here as the test made without mobx-vue doesn't fail, so I presume the problem starts from there.

The environment is: mobx: 5.15.14 mobx-state-tree: 3.17.2 mobx-vue: 2.0.10 vue: 2.6.11

import { mount } from "@vue/test-utils";
import { observer } from "mobx-vue";
import { types, applySnapshot } from "mobx-state-tree";
import { Component } from "vue-property-decorator";
import Vue from 'vue'
const baseType = types.model({
    addresses: types.array(
      types.model({
        city: types.maybeNull(types.string)
      })
    )
  });

@Component({
  name: "sc",
  template: `<div>
  <span v-for="(a, idx) in context.addresses" :key="idx">{{a.city}}</span>
</div>`
})
class Sc extends Vue{
   context = baseType.create()
  };
describe("Vue skel store", () => {
  it("works alone", () => {
    let ctx = baseType.create();
    expect(ctx).toBeDefined();
    expect(ctx.addresses.length).toBe(0);
    applySnapshot(ctx, { addresses: [{ city: "Rome" }] });
    expect(ctx.addresses.length).toBe(1);
    expect(ctx.addresses[0].city).toBe("Rome");
  });
  it("doesn't work when used inside Vue", () => {
    const wrapper = mount(observer(Sc));
    expect(wrapper.text()).toBe("");
    expect(wrapper.vm.context).toBeDefined();
    expect(wrapper.vm.context.addresses.length).toBe(0);
    applySnapshot(wrapper.vm.context, { addresses: [{ city: "Rome" }] });
    expect(wrapper.text()).toBe("Rome");
    expect(wrapper.vm.context.addresses.length).toBe(1);
    wrapper.destroy();
  });
});

the exception raised is:

    TypeError: child.finalizeCreation is not a function
        at /home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1601:27
        at ObjectNode.Object.<anonymous>.BaseNode.baseFinalizeCreation (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1141:17)
        at ObjectNode.Object.<anonymous>.ObjectNode.finalizeCreation (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1596:14)
        at ObjectNode.Object.<anonymous>.ObjectNode.createObservableInstance (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1383:14)
        at executeAction (/home/dev/project/node_modules/mobx/lib/mobx.js:908:19)
        at ObjectNode.createObservableInstance (/home/dev/project/node_modules/mobx/lib/mobx.js:895:16)
        at ObjectNode.Object.<anonymous>.ObjectNode.createObservableInstanceIfNeeded (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1320:18)
        at ModelType.Object.<anonymous>.ComplexType.getValue (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1916:14)
        at ObjectNode.get (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1020:30)
        at ObjectNode.Object.<anonymous>.ObjectNode.unbox (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1587:44)
        at ObservableArrayAdministration.Object.<anonymous>.ObservableArrayAdministration.dehanceValue (/home/dev/project/node_modules/mobx/lib/mobx.js:3057:25)
        at Array.get (/home/dev/project/node_modules/mobx/lib/mobx.js:3318:28)
        at Object.get (/home/dev/project/node_modules/mobx/lib/mobx.js:3004:40)
        at dependArray (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:1134:14)
        at ObjectNode.reactiveGetter [as storedValue] (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:1033:13)
        at ArrayType.Object.<anonymous>.ComplexType.getValue (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1917:21)
        at ObjectNode.get (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1020:30)
        at ObjectNode.Object.<anonymous>.ObjectNode.unbox (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1587:44)
        at ObservableValue.Object.<anonymous>.ObservableValue.dehanceValue (/home/dev/project/node_modules/mobx/lib/mobx.js:1020:25)
        at ObservableValue.Object.<anonymous>.ObservableValue.get (/home/dev/project/node_modules/mobx/lib/mobx.js:1072:21)
        at ObservableObjectAdministration.Object.<anonymous>.ObservableObjectAdministration.read (/home/dev/project/node_modules/mobx/lib/mobx.js:3958:37)
        at Object.get (/home/dev/project/node_modules/mobx/lib/mobx.js:4197:36)
        at Object.reactiveGetter [as addresses] (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:1027:35)
        at Proxy.eval (eval at createFunction (/home/dev/project/node_modules/vue-template-compiler/build.js:4638:12), <anonymous>:1:40)
        at VueComponent.Vue._render (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:3538:22)
        at VueComponent.updateComponent (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:4054:21)
        at Watcher.get (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:4465:25)
        at Watcher.run (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:4540:22)
        at flushSchedulerQueue (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:4298:13)
        at queueWatcher (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:4387:9)
        at Watcher.update (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:4530:5)
        at Dep.notify (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:732:13)
        at Array.mutator (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:884:12)
        at ObservableArrayAdministration.Object.<anonymous>.ObservableArrayAdministration.spliceItemsIntoValues (/home/dev/project/node_modules/mobx/lib/mobx.js:3151:46)
        at ObservableArrayAdministration.Object.<anonymous>.ObservableArrayAdministration.spliceWithArray (/home/dev/project/node_modules/mobx/lib/mobx.js:3143:24)
        at Proxy.replace (/home/dev/project/node_modules/mobx/lib/mobx.js:3222:20)
        at ArrayType.Object.<anonymous>.ArrayType.applySnapshot (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:4453:16)
        at executeAction (/home/dev/project/node_modules/mobx/lib/mobx.js:908:19)
        at ArrayType.applySnapshot (/home/dev/project/node_modules/mobx/lib/mobx.js:895:16)
        at /home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1633:30
        at executeAction (/home/dev/project/node_modules/mobx/lib/mobx.js:908:19)
        at <unnamed action> (/home/dev/project/node_modules/mobx/lib/mobx.js:895:16)
        at runMiddleWares (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:2597:40)
        at runWithActionContext (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:2460:16)
        at ObjectNode.res (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:2487:16)
        at ObjectNode.Object.<anonymous>.ObjectNode.applySnapshot (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1316:14)
        at ArrayType.Object.<anonymous>.ComplexType.tryToReconcileNode (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1938:21)
        at ArrayType.Object.<anonymous>.ComplexType.reconcile (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1944:35)
        at OptionalValue.Object.<anonymous>.OptionalValue.reconcile (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:5562:30)
        at Array.Object.<anonymous>.ModelType.willChange (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:4905:41)
        at interceptChange (/home/dev/project/node_modules/mobx/lib/mobx.js:2957:37)
        at ObservableObjectAdministration.Object.<anonymous>.ObservableObjectAdministration.write (/home/dev/project/node_modules/mobx/lib/mobx.js:3969:26)
        at Object.set (/home/dev/project/node_modules/mobx/lib/mobx.js:4200:29)
        at Object.reactiveSetter [as addresses] (/home/dev/project/node_modules/vue/dist/vue.runtime.common.dev.js:1052:16)
        at /home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:4972:36
        at /home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:5001:60
        at Array.forEach (<anonymous>)
        at ModelType.Object.<anonymous>.ModelType.forAllProps (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:5001:28)
        at ModelType.Object.<anonymous>.ModelType.applySnapshot (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:4971:14)
        at executeAction (/home/dev/project/node_modules/mobx/lib/mobx.js:908:19)
        at ModelType.applySnapshot (/home/dev/project/node_modules/mobx/lib/mobx.js:895:16)
        at /home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1633:30
        at executeAction (/home/dev/project/node_modules/mobx/lib/mobx.js:908:19)
        at <unnamed action> (/home/dev/project/node_modules/mobx/lib/mobx.js:895:16)
        at runMiddleWares (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:2597:40)
        at runWithActionContext (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:2460:16)
        at ObjectNode.res (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:2487:16)
        at ObjectNode.Object.<anonymous>.ObjectNode.applySnapshot (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:1316:14)
        at applySnapshot (/home/dev/project/node_modules/mobx-state-tree/dist/mobx-state-tree.js:406:37)
        at Object.<anonymous> (/home/dev/project/src/datastore/__tests__/vue-store-skel.spec.js:41:5)
        at Object.asyncJestTest (/home/dev/project/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
        at /home/dev/project/node_modules/jest-jasmine2/build/queueRunner.js:43:12
        at new Promise (<anonymous>)
        at mapper (/home/dev/project/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
        at /home/dev/project/node_modules/jest-jasmine2/build/queueRunner.js:73:41
        at processTicksAndRejections (internal/process/task_queues.js:97:5)

but before this, another exception is catched

    TypeError: mobx.getAtom(...).reportObserved is not a function

      39 |     expect(wrapper.vm.context).toBeDefined();
      40 |     expect(wrapper.vm.context.addresses.length).toBe(0);
    > 41 |     applySnapshot(wrapper.vm.context, { addresses: [{ city: "Rome" }] });
         |     ^
      42 |     expect(wrapper.text()).toBe("Rome");
      43 |     expect(wrapper.vm.context.addresses.length).toBe(1);
      44 |     wrapper.destroy();

      at node_modules/mobx-state-tree/dist/mobx-state-tree.js:4947:50
      at node_modules/mobx-state-tree/dist/mobx-state-tree.js:5001:60
          at Array.forEach (<anonymous>)
      at ModelType.Object.<anonymous>.ModelType.forAllProps (node_modules/mobx-state-tree/dist/mobx-state-tree.js:5001:28)
      at ModelType.Object.<anonymous>.ModelType.getSnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:4946:14)
      at ObjectNode.Object.<anonymous>.ObjectNode._getActualSnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1487:26)
      at ObjectNode.Object.<anonymous>.ObjectNode.getSnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1483:20)
      at ObjectNode.get (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1473:32)
      at trackDerivedFunction (node_modules/mobx/lib/mobx.js:757:24)
      at ComputedValue.Object.<anonymous>.ComputedValue.computeValue (node_modules/mobx/lib/mobx.js:1251:19)
      at ComputedValue.Object.<anonymous>.ComputedValue.trackAndCompute (node_modules/mobx/lib/mobx.js:1236:29)
      at invalidateComputed (node_modules/mobx-state-tree/dist/mobx-state-tree.js:3400:10)
      at ObjectNode.Object.<anonymous>.ObjectNode.createObservableInstance (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1377:9)
      at executeAction (node_modules/mobx/lib/mobx.js:908:19)
      at ObjectNode.createObservableInstance (node_modules/mobx/lib/mobx.js:895:16)
      at ObjectNode.Object.<anonymous>.ObjectNode.createObservableInstanceIfNeeded (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1320:18)
      at ModelType.Object.<anonymous>.ComplexType.getValue (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1916:14)
      at ObjectNode.get (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1020:30)
      at ObjectNode.Object.<anonymous>.ObjectNode.unbox (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1587:44)
      at ObservableArrayAdministration.Object.<anonymous>.ObservableArrayAdministration.dehanceValue (node_modules/mobx/lib/mobx.js:3057:25)
      at Array.get (node_modules/mobx/lib/mobx.js:3318:28)
      at Object.get (node_modules/mobx/lib/mobx.js:3004:40)
      at dependArray (node_modules/vue/dist/vue.runtime.common.dev.js:1134:14)
      at ObjectNode.reactiveGetter [as storedValue] (node_modules/vue/dist/vue.runtime.common.dev.js:1033:13)
      at ArrayType.Object.<anonymous>.ComplexType.getValue (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1917:21)
      at ObjectNode.get (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1020:30)
      at ObjectNode.Object.<anonymous>.ObjectNode.unbox (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1587:44)
      at ObservableValue.Object.<anonymous>.ObservableValue.dehanceValue (node_modules/mobx/lib/mobx.js:1020:25)
      at ObservableValue.Object.<anonymous>.ObservableValue.get (node_modules/mobx/lib/mobx.js:1072:21)
      at ObservableObjectAdministration.Object.<anonymous>.ObservableObjectAdministration.read (node_modules/mobx/lib/mobx.js:3958:37)
      at Object.get (node_modules/mobx/lib/mobx.js:4197:36)
      at Object.reactiveGetter [as addresses] (node_modules/vue/dist/vue.runtime.common.dev.js:1027:35)
      at Proxy.eval (eval at createFunction (node_modules/vue-template-compiler/build.js:4638:12), <anonymous>:1:40)
      at VueComponent.Vue._render (node_modules/vue/dist/vue.runtime.common.dev.js:3538:22)
      at VueComponent.updateComponent (node_modules/vue/dist/vue.runtime.common.dev.js:4054:21)
      at Watcher.get (node_modules/vue/dist/vue.runtime.common.dev.js:4465:25)
      at Watcher.run (node_modules/vue/dist/vue.runtime.common.dev.js:4540:22)
      at flushSchedulerQueue (node_modules/vue/dist/vue.runtime.common.dev.js:4298:13)
      at queueWatcher (node_modules/vue/dist/vue.runtime.common.dev.js:4387:9)
      at Watcher.update (node_modules/vue/dist/vue.runtime.common.dev.js:4530:5)
      at Dep.notify (node_modules/vue/dist/vue.runtime.common.dev.js:732:13)
      at Array.mutator (node_modules/vue/dist/vue.runtime.common.dev.js:884:12)
      at ObservableArrayAdministration.Object.<anonymous>.ObservableArrayAdministration.spliceItemsIntoValues (node_modules/mobx/lib/mobx.js:3151:46)
      at ObservableArrayAdministration.Object.<anonymous>.ObservableArrayAdministration.spliceWithArray (node_modules/mobx/lib/mobx.js:3143:24)
      at Proxy.replace (node_modules/mobx/lib/mobx.js:3222:20)
      at ArrayType.Object.<anonymous>.ArrayType.applySnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:4453:16)
      at executeAction (node_modules/mobx/lib/mobx.js:908:19)
      at ArrayType.applySnapshot (node_modules/mobx/lib/mobx.js:895:16)
      at node_modules/mobx-state-tree/dist/mobx-state-tree.js:1633:30
      at executeAction (node_modules/mobx/lib/mobx.js:908:19)
      at <unnamed action> (node_modules/mobx/lib/mobx.js:895:16)
      at runMiddleWares (node_modules/mobx-state-tree/dist/mobx-state-tree.js:2597:40)
      at runWithActionContext (node_modules/mobx-state-tree/dist/mobx-state-tree.js:2460:16)
      at ObjectNode.res (node_modules/mobx-state-tree/dist/mobx-state-tree.js:2487:16)
      at ObjectNode.Object.<anonymous>.ObjectNode.applySnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1316:14)
      at ArrayType.Object.<anonymous>.ComplexType.tryToReconcileNode (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1938:21)
      at ArrayType.Object.<anonymous>.ComplexType.reconcile (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1944:35)
      at OptionalValue.Object.<anonymous>.OptionalValue.reconcile (node_modules/mobx-state-tree/dist/mobx-state-tree.js:5562:30)
      at Array.Object.<anonymous>.ModelType.willChange (node_modules/mobx-state-tree/dist/mobx-state-tree.js:4905:41)
      at interceptChange (node_modules/mobx/lib/mobx.js:2957:37)
      at ObservableObjectAdministration.Object.<anonymous>.ObservableObjectAdministration.write (node_modules/mobx/lib/mobx.js:3969:26)
      at Object.set (node_modules/mobx/lib/mobx.js:4200:29)
      at Object.reactiveSetter [as addresses] (node_modules/vue/dist/vue.runtime.common.dev.js:1052:16)
      at node_modules/mobx-state-tree/dist/mobx-state-tree.js:4972:36
      at node_modules/mobx-state-tree/dist/mobx-state-tree.js:5001:60
          at Array.forEach (<anonymous>)
      at ModelType.Object.<anonymous>.ModelType.forAllProps (node_modules/mobx-state-tree/dist/mobx-state-tree.js:5001:28)
      at ModelType.Object.<anonymous>.ModelType.applySnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:4971:14)
      at executeAction (node_modules/mobx/lib/mobx.js:908:19)
      at ModelType.applySnapshot (node_modules/mobx/lib/mobx.js:895:16)
      at node_modules/mobx-state-tree/dist/mobx-state-tree.js:1633:30
      at executeAction (node_modules/mobx/lib/mobx.js:908:19)
      at <unnamed action> (node_modules/mobx/lib/mobx.js:895:16)
      at runMiddleWares (node_modules/mobx-state-tree/dist/mobx-state-tree.js:2597:40)
      at runWithActionContext (node_modules/mobx-state-tree/dist/mobx-state-tree.js:2460:16)
      at ObjectNode.res (node_modules/mobx-state-tree/dist/mobx-state-tree.js:2487:16)
      at ObjectNode.Object.<anonymous>.ObjectNode.applySnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:1316:14)
      at applySnapshot (node_modules/mobx-state-tree/dist/mobx-state-tree.js:406:37)
      at Object.<anonymous> (src/datastore/__tests__/vue-store-skel.spec.js:41:5)

If necessary, I can provide a more detailed stack-trace

ekobi commented 4 years ago

Seeing the same issue here. @bestmazzo Any progress with your debugging? Almost identical configuration:

kobi@blackbird web $ yarn list | ag 'mobx| vue@'
├─ mobx-state-tree@3.17.2
├─ mobx-vue@2.0.10
├─ mobx@5.15.5
├─ vue@2.6.11
kobi@blackbird web $ 
kuitos commented 4 years ago

Could you pls provide a minimal reproduction?

ekobi commented 4 years ago

FYI, I was able to reproduce this same bug without mobx-vue. A manually-constructed webpack project with a trivial MobX app works as you would expect; but the same trivial app deployed within a vue-cli project fails with these symptoms. I'll update with test case after some sleep.

bestmazzo commented 4 years ago

Well, I'm currently using mobx-vue in a Nuxt application, having a complex data model and multiple libraries involved (some internal widget libraries - deployed with vue-cli - and some third party layout libraries), so this could be a cause. The above jest test is the simplest reproduction I could make, but I'm currently working on recreating a live example with codesandbox.

Meanwhile I've been digging in our code and found out a common misuse:

What actually happens is:

I'll keep digging into it, but I think we should make a specific section in mobx-vue documentation, covering those usage scenarios (vue-cli, mobx-state-tree). in order to help others correctly deal with them.

bestmazzo commented 4 years ago

Hello, I was able to create a codesandbox reproducing the error depicted above: https://codesandbox.io/s/vue-mst-3rueh

Hope this helps better investigating the problem.