1. movue

movue

logo

Movue npm version Build Status Coverage Status License

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