Giter Club home page Giter Club logo

movue's Introduction

Movue npm version Build Status Coverage Status License

Deprecated: This project is not maintained any longer. Since there is an official solution for MobX-Vue.js binding: mobx-vue, you may want to check that.


MobX integration for Vue.js, inspired by vue-rx.

Movue aims for providing simple and reliable integration between Mobx and Vue.js, which sometimes means less convenience. You may want to try mobx-vue if you are facing more complex situation. :)

Why movue

Why MobX + movue, instead of Vuex?

Install

npm i movue --save

If you use yarn,

yarn add movue

Usage

Import Movue in your project and use it in Vue:

import Vue from 'vue'
import Movue from 'movue'
import * as mobx from 'mobx'

Vue.use(Movue, mobx)

You can pass the min parts of MobX to reduce bundle size:

import { reaction } from 'mobx'

Vue.use(Movue, { reaction })

Now you can use data from MobX store in your Vue component:

// given MobX store
const todoStore = observable({
  todos: [],
  get unfinishedTodos() {/* ... */},
  addTodo: action(function() {/* ... */}),
  toggleTodo: action(function() {/* ... */})
  setTodos: action(function() {/* ... */})
})

// given vue component
export default {
  data() {/* ... */},
  computed: {/* ... */},
  // you should use data from MobX store only in `fromMobx` properties
  fromMobx: {
    unfinishedTodos() {
      return todoStore.unfinishedTodos
    }
  },
  methods: {
    toggleTodo(...args) {
      todoStore.toggleTodo(...args)
    }
  }
}

Properties defined in fromMobx can be used in the template or other parts of viewModel just like normal Vue computed properties:

<template>
  <p>Count of unfinished todos: {{unfinishedTodos.length}}</p>
</template>

Like computed properties, we can define getter & setter for fromMobx properties:

export default {
  fromMobx: {
    todos: {
      // getter
      get() {
        return todoStore.todos
      },
      // setter
      set(todos) {
        todoStore.setTodos(todos)
      }
    }
  }
}

You can use helper methods to simplify your code:

import { mapFields, mapMethods } from 'movue'

export default {
  fromMobx: mapFields(todoStore, ['todos', 'unfinishedTodos']),
  methods: {
    // `...` requires object spread syntax support
    ...mapMethods(todoStore, ['addTodo', 'toggleTodo']),
    someOtherMethod() {/* ... */}
  }
}

movue works well with vue-class-component:

import { FromMobx } from 'movue'

@Component({/* ... */})
class Todo extends Vue {
  // get todos
  @FromMobx get todos() {
    return todoStore.todos
  }
  // you don't need decorator for setters
  set todos(todos) {
    todoStore.setTodos(todos)
  }
  // you can also set value with a component method
  setTodos(todos) {
    todoStore.setTodos(todos)
  }
}

API Reference

mapFields(store: object, fieldNames: string[]): Object

mapFields do fields' map for you:

const fields = mapFields(todoStore, ['todos', 'unfinishedTodos'])
// equals
const fields = {
  todos() { return todoStore.todos },
  unfinishedTodos() { return todoStore.unfinishedTodos }
}
mapFields(store: object, fieldNames: {[fieldAlias: string]: string}): Object

You can use aliases for fields:

const fields = mapFields(todoStore, {
  todoList: 'todos',
  unfinishedTodoList: 'unfinishedTodos'
})
// equals
const fields = {
  todoList() { return todoStore.todos },
  unfinishedTodoList() { return todoStore.unfinishedTodos }
}
mapFields(store: object, fieldNames: {[fieldAlias: string]: { get: string, set?: string }}): Object

Also you can specify a setter for the field:

const fields = mapFields(todoStore, {
  todoList: {
    get: 'todos'
  },
  unfinishedTodoList: 'unfinishedTodos',
  newTodoItemName: {
    get: 'newItemName',
    set: 'setNewItemName'
  }
})
// equals
const fields = {
  todoList() { return todoStore.todos },
  unfinishedTodoList() { return todoStore.unfinishedTodos },
  newTodoItemName: {
    get() { return todoStore.newItemName },
    set(value) { todoStore.setNewItemName(value) }
  }
}
mapFields(store: object, fieldNames: {[fieldAlias: string]: { get: (store: object) => any, set?: (store: object, value: any) => void }}): Object

You can specify a complex setter and getter for the field:

const fields = mapFields(todoStore, {
  todoList: {
    get: 'todos'
  },
  unfinishedTodoList: 'unfinishedTodos',
  newTodoItemName: {
    get(store) {
      // store === todoStore
      return store.newItemName
    },
    set(store, value) {
      // store === todoStore
      store.setNewItemName(value)
    }
  }
})
// equals
const fields = {
  todoList() { return todoStore.todos },
  unfinishedTodoList() { return todoStore.unfinishedTodos },
  newTodoItemName: {
    get() { return todoStore.newItemName },
    set(value) { todoStore.setNewItemName(value) }
  }
}
mapMethods(store: object, methodNames: string[]): Object

mapMethods do methods' map for you:

const methods = mapMethods(todoStore, ['addTodo', 'toggleTodo'])
// equals
const methods = {
  addTodo: todoStore.addTodo.bind(todoStore),
  toggleTodo: todoStore.toggleTodo.bind(todoStore)
}
mapMethods(store: object, methodNames: {[methodAlias: string]: string}): Object

You can use aliases for methods:

const methods = mapMethods(todoStore, {
  addTodoItem: 'addTodo',
  checkTodoItem: 'toggleTodo'
})
// equals
const methods = {
  addTodoItem: todoStore.addTodo.bind(todoStore),
  checkTodoItem: todoStore.toggleTodo.bind(todoStore)
}
FromMobx(target: Vue, key: string): void

FromMobx helps to use movue together with vue-class-component. You should use FromMobx as decorator for class property accessors:

@Component({/* ... */})
class Todo extends Vue {
  @FromMobx get todos() {
    return todoStore.todos
  }
}

License

Apache-2.0

movue's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

movue's Issues

在Mobx中定义的数组该如何在Vue中更新?

感谢作者的贡献!

在我们的项目中已经完全使用mobx代替了vuex,并使用了movue,使用过程中发现了不少问题。

首先我想知道我在Mobx中定义的集合,数组该如何在Vue中得到相应呢。

class RenderImgData {
  @observable renderList = [];
}
 fromMobx:{
      watchImgs(){
        var imgs = RenderData.renderImgs;
}

当我在renderList中push元素,发现在vue中并没有得到相应。请问如何能解决这种问题呢

Vue.use TS error No overload matches this call

I cannot setup the movue package. Bellow is my code:
package.json:

"movue": "0.3.2",
"mobx": "5.15.4"

tsconfig.json:

{
	"compileOnSave": false,
	"compilerOptions": {
		"target": "es5",
		"module": "esnext",
		"strict": true,
		"strictNullChecks": false,
		"noImplicitAny": false,
		"noImplicitThis": false,
		"removeComments": false,
		"allowUnreachableCode": false,
		"allowUnusedLabels": false,
		"importHelpers": true,
		"moduleResolution": "node",
		"experimentalDecorators": false,
		"esModuleInterop": true,
		"allowSyntheticDefaultImports": true,
		"sourceMap": false,
		"allowJs": false,
		"baseUrl": ".",
		"types": [ "webpack-env", "jest" ],
		"paths": {
			"@/*": [ "src/*" ]
		},
		"lib": [ "es5", "esnext", "dom", "dom.iterable", "scripthost" ],
		"outDir": "dist"
	},
	"include": [ "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx" ],
	"files": [ "src/shims-vue.d.ts" ],
	"exclude": [ "node_modules" ]
}

main.ts:

import Vue from "vue";

import Movue from 'movue';
import { reaction } from 'mobx';

Vue.use(Movue, { reaction });

Screenshot:
image

Error:

192:9 No overload matches this call.
  Overload 1 of 2, '(plugin: PluginObject<IMobxMethods> | PluginFunction<IMobxMethods>, options?: IMobxMethods): VueConstructor<...>', gave the following error.
    Argument of type '{ install: (Vue: typeof Vue, mobxMethods: IMobxMethods) => void; }' is not assignable to parameter of type 'PluginObject<IMobxMethods> | PluginFunction<IMobxMethods>'.
      Type '{ install: (Vue: typeof Vue, mobxMethods: IMobxMethods) => void; }' is not assignable to type 'PluginObject<IMobxMethods>'.
        Types of property 'install' are incompatible.
          Type '(Vue: typeof Vue, mobxMethods: IMobxMethods) => void' is not assignable to type 'PluginFunction<IMobxMethods>'.
            Types of parameters 'Vue' and 'Vue' are incompatible.
              Type 'VueConstructor<Vue>' is not assignable to type 'typeof Vue'.
                The types of 'config.errorHandler' are incompatible between these types.
                  Type '(err: Error, vm: import("C:/Code/Maximus/src/Maximus.App/node_modules/vue/types/vue").Vue, info: string) => void' is not assignable to type '(err: Error, vm: import("C:/Code/Maximus/src/Maximus.App/node_modules/movue/node_modules/vue/types/vue").Vue, info: string) => void'.
                    Types of parameters 'vm' and 'vm' are incompatible.
                      Type 'Vue' is missing the following properties from type 'Vue': $i18n, $t, $tc, $te, and 6 more.
  Overload 2 of 2, '(plugin: PluginObject<any> | PluginFunction<any>, ...options: any[]): VueConstructor<Vue>', gave the following error.
    Argument of type '{ install: (Vue: typeof Vue, mobxMethods: IMobxMethods) => void; }' is not assignable to parameter of type 'PluginObject<any> | PluginFunction<any>'.
      Type '{ install: (Vue: typeof Vue, mobxMethods: IMobxMethods) => void; }' is not assignable to type 'PluginObject<any>'.
        Types of property 'install' are incompatible.
          Type '(Vue: typeof Vue, mobxMethods: IMobxMethods) => void' is not assignable to type 'PluginFunction<any>'.
            Types of parameters 'Vue' and 'Vue' are incompatible.
              Type 'VueConstructor<Vue>' is not assignable to type 'typeof Vue'.

Anyone knows what is the problem?

Better mobx-vue develop experience

Perhaps we can offer better vue-mobx develop experience by hijack render method of vue component.

Then we can access observable value from MobX store directly in vue components' render method (or template).

It is somewhat like the way mobx-react does. It may not be suitable for vue, as vue provides its own observable mechanism and consume data in more ways (such as computed, watch, ...) other than render method.

But it is worth a try.

MobX 4.0.0 Support

I have been using Movue for a little while now with no problems. I recently updated to MobX 4.0.0 and haven't run into a real issue yet, but a deprecation notice has been popping up in Movue since the update warning a feature being changed.

In MobX 4.0.0, the library is abandoning positional arguments in favor of named arguments. See this function on line 32 of Movue/src/change-detector.ts.

defineReactionList(vm: VueClass, fromMobxEntries: FromMobxEntry[]) {
  const reactivePropertyListKey = this._getReactionListKey(vm)
  const reactivePropertyList: Disposer[] = fromMobxEntries.map(({ key, get }) => {
    const updateReactiveProperty = value => { this.updateReactiveProperty(vm, key, value) }

    // Changed positional argument to named argument
    // OLD: return this.mobxMethods.reaction(() => get.call(vm), updateReactiveProperty, true)
    return this.mobxMethods.reaction(() => get.call(vm), updateReactiveProperty, { fireImmediately: true })
  })

  this.changeDetector[reactivePropertyListKey] = reactivePropertyList
}

See this clip from the MobX 4.0.0 Change Log.

This is the only issue I have found since upgrading to MobX 4.0.0, but will report if I find more. This fix is extraordinarily easy. If I get some free time before this gets patched in, I will submit a pull request, myself. Not sure how much time I'll have soon though.

Great work on this little plugin!
Tresky

Why movue

Why MobX + movue, instead of Vuex?

  1. MobX provides more flexible and powerful observable system (shallow, ref, map...)
  2. You may not like Vuex (action & mutation, the way to compose...)
  3. We want store-realization irrelevant to view-realization (possibility to switch among different view libraries without rewriting store)

添加 CI

  • 添加 CI,执行测试及构建
  • 添加 CI 结果到 README

在component 使用keep-alive的时候出现报错

vue.esm.js:1741 TypeError: Cannot read property 'forEach' of undefined
    at ChangeDetector../node_modules/movue/lib/change-detector.js.ChangeDetector.removeReactionList (change-detector.js:37)
    at VueComponent.beforeDestroy (install.js:27)
    at VueComponent.deactivated (vue-popper.js:200)
    at callHook (vue.esm.js:2921)
    at deactivateChildComponent (vue.esm.js:2910)
    at deactivateChildComponent (vue.esm.js:2908)
    at deactivateChildComponent (vue.esm.js:2908)
    at deactivateChildComponent (vue.esm.js:2908)
    at deactivateChildComponent (vue.esm.js:2908)
    at destroy (vue.esm.js:4180)

在项目中路由使用了keep-alive在来回切换的时候,发现出现以上报错。

查看源码后发现在change-detector.ts中

  removeReactionList(vm: VueClass) {
    const reactivePropertyListKey = this._getReactionListKey(vm)

    this.changeDetector[reactivePropertyListKey].forEach(dispose => dispose())
    delete this.changeDetector[reactivePropertyListKey]
  }

这个方法在执行时出现 this.changeDetector[reactivePropertyListKey]未定义。

改为 this.changeDetector[reactivePropertyListKey] && this.changeDetector[reactivePropertyListKey].forEach(dispose => dispose()) 就不会出错了。

具体出错原因好像是vue执行了beforeDestory,但vm还存在,导致第二次还会执行这个方法。

请问是我哪里用错了吗

Add support for fromMobx attributes being pulled from mixins

I have run into a limitation of Movue while working on an application. The current functionality of the library does not allow loading fromMobx attributes from a mixin on a component. See example below:

const data = observable({
  foo: 1
})

const mixin = {
  fromMobx: {
    foo () {
      return data.foo
    }
  }
}

const vm = new Vue({
  mixins: [mixin],
  computed: {
    value () {
      // This value will be undefined in the current version.
      // This PR allows this to work.
      return this.foo
    }
  },
  render (h) {
    const vm: any = this
    return h('div', `${vm.value}`)
  }
})

As it stands, right now, the value foo will not be defined in the top-level component. This pull request pulls fromMobx attributes from mixins one-level below the top-level component to allow Movue to be used in mixin abstraction.

I have submitted a Pull Request at #21

EDIT: Spelling and adding a comment.

Changes in nested objects not being tracked?

Hi there, thanks a ton for this integration!

While evaluating Vue with mobx-state-tree, I've been getting issues trying to track changes in nested objects, as if only the things listed in fromMobx are defined as reactive.

Then I found this change and I am curious about the motivation behind using the shallow option. Was this performance? Other? It looks like vue-rx does not do that

To help, here is my code:

  computed: {
    item() {
      return this.project.item
    },
  },
  fromMobx: {
    project() {
      return shop.projects.getFirst()
    },
  },
  methods: {
    updateItem() {
      this.project.setItem(this.newItem)
    }
  }

shop.projects being a mobx-state-tree store, with a setItem function that updates the project.item. mobx-state-tree being immutable, project.item effectively points to a different observable, but movue does not track the change

Let me know your thoughts

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.