Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception when using with mobx-state-tree #51

Open
bestmazzo opened this issue Aug 20, 2020 · 5 comments
Open

Exception when using with mobx-state-tree #51

bestmazzo opened this issue Aug 20, 2020 · 5 comments

Comments

@bestmazzo
Copy link

bestmazzo commented Aug 20, 2020

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
Copy link

ekobi commented Aug 25, 2020

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

kobi@blackbird web $ yarn list | ag 'mobx| vue@'
├─ [email protected]
├─ [email protected]
├─ [email protected]
├─ [email protected]
kobi@blackbird web $ 

@kuitos
Copy link
Member

kuitos commented Aug 25, 2020

Could you pls provide a minimal reproduction?

@ekobi
Copy link

ekobi commented Aug 27, 2020

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
Copy link
Author

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:

  • we've been assuming MST node method toJSON() creates a plain JS object structure we could safely pass down to functional components (e.g. layout ones or form elements)
  • given the above assumption we didin't wrap all components using mobx-vue observer() method and felt safe to pass data to third party components

What actually happens is:

  • MST toJSON() method actually returns a shallow copy of the involved tree not a deep copy
  • when passing down this structure, subcomponents involved are dealing with a real MST node, but they're not forced to use mobx-vue wrap.

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
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants