mobxjs / mobx-vue Goto Github PK
View Code? Open in Web Editor NEW🐉 Vue bindings for MobX
License: MIT License
🐉 Vue bindings for MobX
License: MIT License
I have a case where I pass component definition directly to vue meta component.
<component :is="{..component definition}" v-bind="props"/>
wrapping it with observer breaks a whole thing.
Do you have any idea what to do here?
I create two stores, one a mobx store and one a mobx-state-tree store. I then hooked them both up to a vue view, per the readme. The mobx store works (i.e component updates when the store changes), but the view does not update on changes in the mobx-state-tree store.
When unit testing Vue components, it is often necessary to call await vm.$nextTick()
to ensure the rerender is completed before accessing the component's DOM for assertion.
As far as I understand, mobx-vue
triggers the rerender directly, and has nothing to do with Vue's Async Update Queue. Therefore vm.$nextTick
would not work for mobx-vue.
So the question is how would one do the same thing as nextTick
with mobx-vue
?
How can i detect mobx variable changing in vue ? Thx
Pls help, why is not working
This is demo https://codesandbox.io/s/lj3l95m09
Thx!
here is the code, models
import { action, observable, configure } from "mobx";
configure({enforceActions: true}) // strict mode
export default class ViewModel {
@observable data = [];
@action.bound load() {
setTimeout(() => {
this.data = [{ age: 18, name: 'aaa' }, { age: 19, name: 'bbb' }]
}, 1500);
}
}
vue component:
<template>
<div class="hello">
<pre>
{{state.data}}
</pre>
</div>
</template>
<script>
import { observer } from "mobx-vue";
import User from '../models/test.js'
export default observer({
name: 'HelloWorld',
mounted() {
this.state.load()
},
data() {
return {
state: new User()
}
}
})
</script>
Uncaught Error: [mobx] Since strict-mode is enabled, chang...
The mobx strict mode is useful to prevent some unnecessary problem. I tried add action in vue compoent, it doesn't work, has any way to enable strict model ?
It was working fine before installing and add mobx to vuejs
main.js
import Vue from 'vue/dist/vue.js'
import VueRouter from 'vue-router'
import App from './components/app/App'
import router from './routers'
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App Template:
<div id="app">
<router-link to="/home">Home</router-link>
<router-view></router-view>
</div>
App Script:
import { observer } from 'mobx-vue';
import Store from '../../stores/store';
export default observer({
name: 'app',
components: {},
data() {
return { state: new Store() };
}
});
I've got this error:
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
vue.runtime.esm.js?2b0e:619 [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
If using observable for COLLECTION, we got error while access any property of object.
export class VM {
@observable histories: any[] = []
constructor() {
makeObservable(this)
this.loadData()
}
@action.bound loadData() {
this.histories = [
{ id: 1, name: 'test1' },
{ id: 2, name: 'test2' },
]
console.log(this.histories)
}
}
Since mobx v6 and vue v3 was released for a while, it's time to support mobx v6 and vue v3.
Vue 3 Compatibility #50
Module Browser Build #49
Can I use mobx-vue without decorated class properties? #47
Add Documentation re Optimizing Rendering #36
Nuxt support #26 #32
Thoughts about mobx-vue #3 (comment)
I'm kinda wondering what direction this project might take with a "new vue" on the horizon. Since vue seems to move away from classes and therefore decorators is there a happy path to using mobx with vue in 2020?
vue-class-component has their own problem
vuejs/vue-class-component#406
export a vue plugin for vue3
import { createApp } from 'vue';
import MobxVuePlugin from 'mobx-vue';
import App from './App.vue';
createApp(App)
.use(MobxVuePlugin, { name: 'MyObserver' /** optional Observer component name */ })
.mount('#app');
Using Observer Component in your app
<template>
<Observer>
<div>name: {{data.name}}</div>
<button @click="changeName">change</button>
</Observer>
</template>
<script setup>
import { runInAction, observable } from mobx;
const data = observable({ name: "iChenLei" });
const changeName = () => {
runInAction(() => { data.name = "Kuitos" });
};
</script>
export a observer
function to hack vue export default
, no need to install as plugin, you can use it directly.
<template>
<UserComponent />
<ProfileComponent />
</template>
<script>
import { observer } from 'mobx-vue';
export default observer({
setup() {
// balabala
}
});
</script>
<!-- use @ decorator -->
<script>
import { observer } from 'mobx-vue';
@observer
export default {
setup() {
// balabala
}
};
</script>
But it not easy to do this , we need hack the vue @internel (e.g. $
, $options
, $forceUpdate
)
// vue 3 internal component properties map
const publicPropertiesMap: PublicPropertiesMap = extend(Object.create(null), {
$: i => i,
$el: i => i.vnode.el,
$data: i => i.data,
$props: i => (__DEV__ ? shallowReadonly(i.props) : i.props),
$attrs: i => (__DEV__ ? shallowReadonly(i.attrs) : i.attrs),
$slots: i => (__DEV__ ? shallowReadonly(i.slots) : i.slots),
$refs: i => (__DEV__ ? shallowReadonly(i.refs) : i.refs),
$parent: i => getPublicInstance(i.parent),
$root: i => getPublicInstance(i.root),
$emit: i => i.emit,
$options: i => (__FEATURE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type),
$forceUpdate: i => () => queueJob(i.update),
$nextTick: i => nextTick.bind(i.proxy!),
$watch: i => (__FEATURE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP)
} as PublicPropertiesMap)
And when you use <script setup>
, it's also diffcult to implement a useful observer
function.(any suggestion for this welcome)
add the template sugar like <template pug>
, <template functional>
.
<tempalte observer>
<UserProfile />
<template>
It looks like best solution for mobx-vue and vue sfc? But it need mobx-vue maintainer to maintian different tools to support this feature. (e.g. mobx-vue-loader
for webpack
, rollup-plugin-mobx-vue
for vite
and rollup
, ...etc). Not a reliable choice i think. I didn't see any api allow us to change the <template>
behavior. It's parsed by @vue/compiler-sfc
and no public api.
Deprecate vue-class-component
and make vue sfc
as first class support.
Any idea and disscussion welcome, maybe you can design the final mobx-vue v3 api.
I got a project with no decorated class properties. Trying to use mobx-vue instead of vuex. Vuex seems too complicated. The second reason it has no TS support.
Based on your small example https://github.com/mobxjs/mobx-vue/blob/master/README.md the ViewModel is created using decorated properties. Just wondering if I can create a viewmodel with pure typescript.
Is it possible?
Basically i want to add my state globally through install fn, but I can't seem to find any examples.
export default {
install(Vue, options) {
// this will work, but wont be observable by component
Vue.prototype.state = new StateClass()
// I want to add mobx on this step, state above will work, but wont be observable
Vue.component('MyCustomComponent', Vue.extend(MyCustomComponent))
}
}
Need some start boilerplates vue with mobx-vue. I tried to put to work vue-cli 3.0.4 (vue 2.5.17) with mobx-vue 2.0.7 and mobx 5.5.0 with babel or ts and had unsolved problems with decorators:
vue.runtime.esm.js?2b0e:587 [Vue warn]: Error in data(): "Error: Decorating class property failed. Please ensure that proposal-class-properties is enabled and set to use loose mode. To use proposal-class-properties in spec mode with decorators, wait for the next major version of decorators in stage 2."
found in
---> <Object> at src/App.vue
<Root>
warn @ vue.runtime.esm.js?2b0e:587
vue.runtime.esm.js?2b0e:1737 Error: Decorating class property failed. Please ensure that proposal-class-properties is enabled and set to use loose mode. To use proposal-class-properties in spec mode with decorators, wait for the next major version of decorators in stage 2.
at _initializerWarningHelper (initializerWarningHelper.js?ec94:2)
at new ViewModel (ViewModel.js?b643:2)
at VueComponent.data (App.vue?234e:7)
at collectData (collectData.js?2679:8)
at VueComponent.data (observer.js?3172:17)
at getData (vue.runtime.esm.js?2b0e:3413)
at initData (vue.runtime.esm.js?2b0e:3370)
at initState (vue.runtime.esm.js?2b0e:3307)
at VueComponent.Vue._init (vue.runtime.esm.js?2b0e:4624)
at new Object (vue.runtime.esm.js?2b0e:4794)
logError @ vue.runtime.esm.js?2b0e:1737
Hello,
I've installed the package from npm and i was getting this error:
Module not found: Error: Can't resolve './observer' in '/Users/........./node_modules/mobx-vue/esm'
The file seems to be missing indeed from the package after checking node_modules.
This is just a heads-up! I had to (re)build the project and move the files manually to get it working. Other than that, nice job!
This is my code
<template>
<div class="test">
<p>{{testMobx.data}}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { Observer } from 'mobx-vue'
import { observable } from 'mobx'
class TestMobx {
@observable data = 123
}
let TestClass = new TestMobx()
@Observer
@Component
export default class App extends Vue {
testMobx = TestClass
}
</script>
but has this warning:
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
why??
https://github.com/mobxjs/mobx/blob/master/CHANGELOG.md#500
.$mobx
propertyIs there a way to make this reactive?
<my-component :my-prop="someMobxModelObject"></my-component>
Hey,
Is any common pattern for mobx-vue which is similar to using Provider decorator from a mobx-react?
Also I have a question about using it with routing. Can I inject specified substore/ substores to exact route?
Hi guys, I'd like to use mobx and vue isomorphic, which is the best way to achieve this??? would be great if mubx would be incorporated to nuxt as alternative to redux...any plan for this???
thank you guys for the great job...
When I download mobx-vue, it comes with version 2.0.11 and doesn't work with mobx6, it gives a webpack object error in the console.
Does this plugin work for vue.js with mobx 6 without using @pattern?
Thanks.
<template>
<section>
<p v-text="age"></p>
<p v-text="computedAge"></p>
<p v-for="user in users" :key="user.name">{{user.name}}</p>
<button @click="setAge"></button>
</section>
</template>
<script lang="ts">
import { Connect } from "mobx-vue";
import Vue from "vue";
import Component from "vue-class-component";
import ViewModel from './ViewModel';
@Connect(new ViewModel())
@Component()
export default class App extends Vue {
mounted() {
this.fetchUsers();
}
}
</script>
这是目前官方给的例子,想问下如果有多个Mobx 的store,该如何使用呢?我这样的使用可以被支持吗?
<template>
<section>
<p v-text="age"></p>
<p v-text="computedAge"></p>
<p v-for="user in users" :key="user.name">{{user.name}}</p>
<button @click="setAge"></button>
<p>{{ViewModel.user}}</p>
</section>
</template>
<script lang="ts">
import { Connect } from "mobx-vue";
import Vue from "vue";
import Component from "vue-class-component";
import ViewModel from './ViewModel';
import ViewModel2 from './ViewModel2';
@Connect()
@Component()
export default class App extends Vue {
mounted() {
this.fetchUsers();
}
computed:{
user(){
return ViewModel.user
},
user2(){
return ViewModel2.user
}
}
}
</script>
Is there a module (ES2015/ES6) browser build to correspond to the Vue module browser build?
Example Vue Browser Builds
When creating a page (i.e. a component under the pages
directory) in NuxtJS, this
is undefined
in data()
when the component is an observer
.
mobx6?
I use Nuxt + typescript and run with 'universal' mode.
I got error when I refresh browser with this code
@Observer
@Component()
export default class Home extends Vue {
mounted () {
}
}
Is don't have any error when I try with
export default observer({
mounted () {
}
});
error TypeError: Cannot convert undefined or null to object
at Function.getOwnPropertyNames ()
at Home.Component._init (vendors.app.js:2672)
at Home.Vue (commons.app.js:16802)
at new Home (inspire.js:64)
at collectDataFromConstructor (vendors.app.js:2692)
at data (vendors.app.js:2767)
at collectData (inspire.js:28)
at VueComponent.data (inspire.js:111)
at VueComponent.Component.options.data (app.js:3171)
at getData (commons.app.js:16467)
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
Hi @mweststrate
Recently I built this library to combine mobx with vue through a simple api what like mobx-react does, now it released v1.0.0 and reached 100% code coverage already, could you please donate some time to make a review and check is it good enough to move to mobxjs organization?
We run into a common problem using this library and vuetifyjs, and I think this library could be extended to offer a few basic components/functions to solve those issues with $scopedSlots
. Bear with me for more detail.
When using a component such as v-data-table
, we have a mandatory scoped slot. The problem with scope slots is that they're not part of the render of the current component, by current I mean the one we see in our SFC. Anything within a scoped slot is rendered as part of the render of the child component. So outside of the @Observer
'guard'.
My thought process was, maybe we could add a function to this library, that given a component wraps all $scopedSlots
with a observer annotation? So that way, instead of using the v-data-table
component from vuetify, I would use my data-table
component which would be something akin to:
import { observerWithScopedSlots } from 'mobx-vue';
import VDataTable from 'vuetify/lib/components/VDataTable/VDataTable';
export default DataTable = observerWithScopedSlots(VDataTable);
Thoughts?
<template>
<div class = "overlook-setting">
{{testMobx.data}}
</div>
</template>
<script>
import { Component, Vue } from 'vue-property-decorator'
import { observable, action } from 'mobx'
class TestMobx {
constructor() {
}
@observable data = 9
@action.bound setData() {
this.data++
}
}
let TestClass = new TestMobx()
@Component
export default class OverlookSetting extends Vue {
testMobx = TestClass
mounted() {
this.testMobx.setData()
this.testMobx.data++
console.log(this.testMobx.data)
}
beforeDestroy() {
}
}
</script>
<style lang = "less" scoped>
.overlook-setting {
}
</style>
当我运行上面这段代码的时候打印出来的数据是10 ,但Dom还是9
Vue版本2.5.16 ,Mobx版本4.3.1
I want to ask if this will work if i added a new instance of my store as a vue instance prototype object
Vue.prototype.$todoStore=new TodoViewModel()
And use in all my components as this.$todoStore
as opposed to creating a new instance of the store in each component.
When using mobx computed inside vue computed, vue computed don't get updated.
https://codesandbox.io/s/m5k1yrn2xx
click add
Do the mobx-react
best practices regarding component composition and de-referecning equally apply to mobx-vue
?
Does this library work same same, any other obvious advice?
see details: #3
Hello,
First of all, I am quite new to Vue, so I might have missed some documentation. I have used Mobx in combination with React, and haven't had any issues there regarding views not being updated.
Secondly, I have a quite complex construction, where I inject my stores via Inversify in order to have some sort of IoC-layer between my components and stores.
This works, however, correctly as far as I can see.
But, it works as long as I use the observable
properties from my stores directly in my template. Using the @Observer
-decorator, my views update and everything is fine.
However, I am using vee-validate for validating my forms. I have Vee-validate's observer around my form, in which a button exists. This button is listening to a loading state in my store, and should be updated whenever the loading state changes.
For example:
There is a login form, when clicking the button Vee-validate's observer checks whether all required inputs are filled.
When that is the case, the login method is called. This login method triggers a method in the store. At that point, the loading state is set to loading, which should update the button in the template.
The store method does some things with the API to check whether the user can be logged in, whereafter the loading state is set to "loaded".
And there it goes wrong. I can see in my template that the state goes back to loading. But it doesn't switch to "loading" in Vee-validate's observer. I have to change an input in order to trigger a re-render, before the button is switched back to the already switched store loading state.
This can be seen in this video: https://imgur.com/a/1NsNevz
The true/false is the same loading state indicator as is used in the button. As can be seen, the true/false at the bottom is updated when the action is done loading. The button however doesn't update until I type.
You can also see some error messages appearing at the top. These are also handles with stores and injected in components.
The code for the Vue component I am using:
https://gist.github.com/emachiels/81fd1b0e552bb536d499db75b3dd153f
And the code for the cocStore:
https://gist.github.com/emachiels/ae7ca3d6fcbea6e3c06644cef0368df6
Does someone know what the problem is?
Thanks in advance!
-- EDIT --
I am using the following versions:
Mobx: 5.15.4
Mobx-Vue: 2.0.10
Vue: 2.6.11
Vee-validate: 3.3.3
Please publish a new version to include some fixes, e.g:
98b2f7f#diff-16f9b99c2cd30a22750975a7d8cc169a
Using @Observer
with @Component
does not copy static properties
Updated hook not called after model update
如何在全局创建一个store?如何像vuex一样创建一个全局的store,例如:
import store from './app/vuex/store.js';//引用store
import router from './app/router/router.js';//引用router
//创建vue实例
window.myvue = new Vue({
el: '#app'
,store:store//把store给root vue
,router:router //通过vue配置中的router挂载router实例
,render: h => h(App)
});
创建一个全局组件后,在每一个组件子组件中都可以通过this.$store来获取这个store。
目前mobx-vue似乎只能针对一个vue创建一个store,子组件不知道用什么方法获取这个呢?
Thank you for all your work with Mobx-vue and helping make Mobx work with Vue! I've just started working with MobX + Vue and liking it a lot so far.
One question I had was about any dev tooling available that is stack agnostic or Vue specific, as it looks like the Mobx chrome dev tools and Delorean for time travel debugging is Mobx + React only? If there isn't any at the moment, are there plans for this in the future?
mobx-vue doesn't seem to work with Vue 3 (https://v3.vuejs.org/). Is there going to be an update for that?
<template>
<div class = "overlook-setting">
<div v-if = "isShow">
{{testMobx.data}}
</div>
</div>
</template>
<script>
// import { Component, Vue } from 'vue-property-decorator'
import { observable, action } from 'mobx'
import { observer } from 'mobx-vue'
class TestMobx {
constructor() {
}
@observable data = {
x: 0,
y: 0,
z: 0,
}
@action.bound setData() {
this.data.x++
}
}
let TestClass = new TestMobx()
setTimeout(() => {
TestClass.setData()
}, 3000)
export default observer({
data() {
return {
isShow: false,
testMobx: TestClass
}
},
mounted() {
this.isShow = true
}
})
</script>
<style lang = "less" scoped>
.overlook-setting {
}
</style>
当模板渲染加入v-if后,Dom响应会失效。
页面理论应该在2000后显示 {x:1} ,可是一直会停在{x:0}
mobx-vue是支持vue3.0的吗?想确认一下
Hi there! I've read the docs and came with some ideas:
Mostly what we want is to connect Store instance with Component instance/element, instead of to connect Store instance with Component class/definition. The later may introduce issues when the same Component class/definition used (instantiated) multiple times - different Component instance/element will share the same state. Such behavior suits global-state-situation, while not local-viewModal-state-situation.
Maybe connect
is not a good idea. connect
defines extra properties on Vue vm in an implicit way. IMO, it will be better not to provide the ability of connect
. Offering ability of observer
allows developer to organize their state in more explicit way, maybe something like:
@observer // assuming that we provide `observer` like mobx-react
@Component()
export default class App extends Vue {
viewModel = new ViewModel() // which means `viewModel.age` in template
}
What do you think?
codesandbox: https://codesandbox.io/s/gallant-butterfly-3clxm
Maybe it should be reaction.getDisposer_
?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.