Code Monkey home page Code Monkey logo

vuex's Introduction

Vuex

npm ci status


Pinia is now the new default

The official state management library for Vue has changed to Pinia. Pinia has almost the exact same or enhanced API as Vuex 5, described in Vuex 5 RFC. You could simply consider Pinia as Vuex 5 with a different name. Pinia also works with Vue 2.x as well.

Vuex 3 and 4 will still be maintained. However, it's unlikely to add new functionalities to it. Vuex and Pinia can be installed in the same project. If you're migrating existing Vuex app to Pinia, it might be a suitable option. However, if you're planning to start a new project, we highly recommend using Pinia instead.


Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official devtools extension to provide advanced features such as zero-config time-travel debugging and state snapshot export / import.

Learn more about Vuex at "What is Vuex?", or get started by looking into full documentation.

Documentation

To check out docs, visit vuex.vuejs.org.

Examples

You may find example applications built with Vuex under the examples directory.

Running the examples:

$ npm install
$ npm run dev # serve examples at localhost:8080

Questions

For questions and support please use the Discord chat server or the official forum. The issue list of this repo is exclusively for bug reports and feature requests.

Issues

Please make sure to read the Issue Reporting Checklist before opening an issue. Issues not conforming to the guidelines may be closed immediately.

Changelog

Detailed changes for each release are documented in the release notes.

Stay In Touch

For latest releases and announcements, follow on Twitter: @vuejs.

Contribution

Please make sure to read the Contributing Guide before making a pull request.

License

MIT

Copyright (c) 2015-present Evan You

vuex's People

Contributors

38elements avatar alex-sokolov avatar angeliski avatar bichikim avatar blake-newman avatar cedric25 avatar cuebit avatar dependabot[bot] avatar djyde avatar dobbsryan avatar dollinad avatar fnlctrl avatar gbezyuk avatar hootlex avatar hq5544 avatar jingsam avatar jinjiang avatar kazupon avatar kiaking avatar kingmario avatar ktsn avatar lanzhiheng avatar linusborg avatar machinisteweb avatar nrdsp avatar periscuelo avatar posva avatar simplesmiler avatar yyx990803 avatar zigomir avatar

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

vuex's Issues

Usage with Voie (or similar router)

I am looking at Voie as a really good alternative to vue-router. I like the approach, syntax and simplicity.

I managed to use Vuex with Voie's example app by loading the data inside each component instead of passing the data into the component from the outside, in this case from Voie's state manager.

Voie routes have a method called enter() that allows to load data before rendering the component, and then pass it trough, assuring the component is loaded after the data has arrived. When using Vuex actions this is harder to do as the action does not return a promise, and the component is renderd before the data arrived.

The approach I want to achieve is to pass Vuex data/state from the router into a component after the data has loaded.

I opened an issue there inca/voie#5 , but it's also related to this issue here #11 about getting it to work with vue-router.

Thanks.

Where to follow latest changes?

Suddenly we are already at version 0.6.1 (at least at the moment I'm writing this)...

Is there a place (maybe a forum thread) where the latest changes are announced?

Please, let me know. I want to be using latest version, but I'm not sure if there are significant or breaking changes, or not.

Thank you!

Return value in actions

I tried to return some value in actions. But i found out that the value received in components is always undefined. (For some reason I don't want to use states here.) Is it a bug?

Vuex Dist?

Hello @yyx990803, do you plan to release a dist build for vuex ?

I use tonicdev at the moment as a playground but would love to see vuex integrated in cdnjs to embed it as an external resource on JSFiddle/Codepen.

Thanks in advance 👍

异步操作中无法修改state的属性

export default {
  [type.GET_PAPERS] (state, force = false) {
    fetch(`${apiUrl}/api/paper`).then(r => r.json())
    .then(data => state.papers = data) // Error: [vuex] Do not mutate vuex store state outside mutation handlers.
    // state.papers = [1, 2, 3, 4] // ok
  }
}

当我切换视图的时候, 这个 view下 vuex store 的 state 仍被保留了。

列子:视图 A B 是通过 vue router 来切换的。 视图A 本来有一部分内容是 隐藏的。

state : {
 isShowAnything : false
}

再通过 action 改变了 sate的状态 isShowAnything = true 的时候, view a 中内容被显示。

这个时候 切换view 到 b, 再切换回 a...
默认被隐藏的内容仍是显示状态(因为是通过vue router切换的,所以 view 肯定是被销毁了, 我在 vue devtools里看 view的 props data已经重置)

这里的问题就很像 component 被 keep-alive了。

我不清楚 vuex 设计的时候 就是这样的,还是我使用中理解错了。还请解答一下,谢谢。

PS:因为英文组织能力较差,怕用英文提issues描述的更混乱,所以用中文提问,还请谅解。

Bower support

Hi, is there any reason why vuex isn't registered with Bower?

If not, I can perfectly well do a merge request for a Bower.json.

Thanks!

semver

I'll be that guy.

0.5.0 won't work with my code I've written with 0.2.0.

through out my application I'm accessing my store actions like:

// application/store/index.js
import vuex from 'vuex';

import store from './store';
import mutations from './mutations';
import actions from './actions';
import middlewares from './middlewares';

const store = new Vuex.Store({
    state,
    mutations,
    actions,
    middlewares,
});

export default store;

application/states/root.vue

<template>
  <input type="text" v-model="foo">
</template>

<script>
import store from 'application/store';

export default {
  computed: {

    foo: {
      get () { store.state.Foo; },
      set (value) { store.actions.updateFoo(value); } ,
    }

  }
};
</script>

This throws:

TypeError: Cannot read property 'updateFoo' of undefined

I would have only expected this when moving to 1.x.x

Config error after fresh vuex install

After fresh npm and vuex installs while using browserify, creating new Vue.store continuely throws calendar_component.js:10205Uncaught TypeError: Cannot read property 'config' of undefined.

Opening up the error reveals this code:

function Store() {
      var _this = this;

      var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

      var _ref$state = _ref.state;
      var state = _ref$state === undefined ? {} : _ref$state;
      var _ref$mutations = _ref.mutations;
      var mutations = _ref$mutations === undefined ? {} : _ref$mutations;
      var _ref$modules = _ref.modules;
      var modules = _ref$modules === undefined ? {} : _ref$modules;
      var _ref$middlewares = _ref.middlewares;
      var middlewares = _ref$middlewares === undefined ? [] : _ref$middlewares;
      var _ref$strict = _ref.strict;
      var strict = _ref$strict === undefined ? false : _ref$strict;
      babelHelpers.classCallCheck(this, Store);

      this._dispatching = false;
      this._rootMutations = this._mutations = mutations;
      this._modules = modules;
      // bind dispatch to self
      var dispatch = this.dispatch;
      this.dispatch = function () {
        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        dispatch.apply(_this, args);
      };
      // use a Vue instance to store the state tree
      // suppress warnings just in case the user has added
      // some funky global mixins
      var silent = Vue.config.silent;
      Vue.config.silent = true;
      this._vm = new Vue({
        data: state
      });
      Vue.config.silent = silent;   \\---------------> this is the line of the error here\\
      this._setupModuleState(state, modules);
      this._setupModuleMutations(modules);
      this._setupMiddlewares(middlewares, state);
      // add extra warnings in strict mode
      if (strict) {
        this._setupMutationCheck();
      }
    }

I have no idea why this is happening, i tried to reinstall both but continue with this error. Here is my root vue instance where i am trying to start the vuex store.

// browserify entrypoint

var Vue = require('vue');
import Vuex from 'vuex';

import calendarHeader from './components/Header.vue';
import calendarSettings from './components/Settings.vue';
import calendarContent from './components/Contents.vue';

const state = {
    count: 0
}

const mutations = {
    INCREMENT (state) {
        state.count++
    }
}

const store = new Vuex.Store({
    state,
    mutations
});

new Vue({

    store,

    el: '#calendar',

    components: { calendarHeader, calendarSettings, calendarContent},

    ready: function() {

        console.log('Ready too go!');
        console.log(store.state.count) // -> 1
    },

    methods: {

        parallax: function() {

            var velocity = 0.4;
            var pos = $('#calendar').scrollTop();
            var scr = Math.round((0 - pos) * velocity);

            $('.current_day_header .header_window').css('backgroundPosition', '0 ' + scr +  'px');

                if(scr < -200){
                    scr = -200;
                }
        }

    }
});

How do i resolve this error? so fare i removed everything and narrowed it down to this line

const store = new Vuex.Store({

Can someone help me?

Improve API for better module composition

I am working on a reusable widget which will be used in a SPA based on vue/vuex. I found it a little bit tricky to expose the mutation/action/state of the widget to the SPA. I had to transform the original mutation/action/state to some form that could be composed together (https://github.com/blu3gui7ar/b9-modeler/blob/develop/src/store/index.js#L36). But I think there should be some official recommendations.

In redux, reducer composition is considered as the fundamental pattern of building Redux apps. The combineReducers(reducers) API helps composite reusable widgets together.

An example for a multi-language app with vue-router

Hi !

I see a lot of comments talking about multi-language / vue-router and vuex.
#1 #2 #3

Internationalisation is missing in Vue.
And I think, it should be in the core system.

We have some good plugins like i18n
But it's not mature to be used in production see

I can't figure it out, what is the best way to do this?
Shouldn't this useful example be in the roadmap ?

To resume, we need

  • navigation change the language at the runtime (update history, and link)
  • different named route for the same page
  • possibility to load and insert data via ajax
  • possibility to access from anywhere to the hardcoded/dynamique data
  • possibility to inject data from a child component

This is my first approach but i know i'm wrong (using vue-router and vue-i18n).

route.js

import Vue from 'vue'
import p404 from './pages/404/404.vue'
import Home from './pages/home/Home.vue'
import About from './pages/about/About.vue'
import Work from './pages/work/Work.vue'
import Contact from './pages/contact/Contact.vue'

module.exports = function(router){

    router.map({
        '*': { component: p404 }, 

        '/': { name: 'home-en', component: Home, lang: 'en' }, 
        '/about': { name: 'about-en', component: About, lang: 'en' }, 
        '/work': { name: 'work-en', component: Work, lang: 'en' }, 
        '/contact-us': { name: 'contact-en', component: Contact, lang: 'en' },

        '/accueil': { name: 'home-fr', component: Home, lang: 'fr' }, 
        '/a-propos': { name: 'about-fr', component: About, lang: 'fr' }, 
        '/travaux': { name: 'work-fr', component: Work, lang: 'fr' }, 
        '/contactez-nous': { name: 'contact-fr', component: Contact, lang: 'fr' }
    })

  router.beforeEach(function (transition) {
    Vue.config.lang = transition.to.lang
    transition.next()
  })

}

navigation.vue

<template>
  <div class="Navigation">
    <div class="Navigation__link-wrapper">
      <a class="Navigation__link" 
        v-for="btn in menu" 
        v-link="{ name: btn.route, activeClass: 'Navigation__link--active' }">
          {{ $t(btn.name) }}
      </a>
      <a href="#" @click.prevent="changeLang">
        toggle lang
      </a>
    </div>
  </div>
</template>

<script>
  import Vue from 'vue'

  export default {
    data() {
      return {
        lang: Vue.config.lang
      }
    },
    computed: {
      menu() {
        return [
          { route: 'about-' + this.lang, name: "navigation.about" },
          { route: 'work-' + this.lang, name: 'navigation.work' },
          { route: 'contact-' + this.lang, name: 'navigation.contact' },
        ]
      }
    },
    methods: {
      changeLang() {
        this.lang = (this.lang == 'fr') ? 'en' : 'fr'
      },
    }
  }
</script>

Any help will be appreciate !

Limitation of mutations when passed 'state' rather than store

How is one supposed to set nested keyPaths in state mutations, given that mutations only receive state and not store and therefore by implication no $set() method?

Take for instance the following, in the examples:

[DECREMENT] (state) {
  state.count--
}

.. which is fine if you need to set or replace a root level keyPath

... but what when you need to set something nested, eg:

[UPDATE] (state, keyPath, value) {
    // keyPath = state.user.userData.presence.status
}

What's the 'vue-y' way to change the value?

Using Baobab, we could set a cursor to that point or using the $set () method we could specify the dot notation keypath ... but when we only have the state object ... ?

State.obj doesn't work

I tried inside a mutation to to state.obj = defaultStateBuilder() that return a fresh object with the initial default state but it doesn't work as the docs say it should. In the end I had to do this:

_.pairs(newState).map((x) => Vue.set(state, x[0], x[1]))

But I would assume that state.obj = newState should work according to the section "Mutations Follow Vue's Reactivity Rules" in http://vuex.vuejs.org/en/mutations.html

About mutations usefulness

What should I do inside a mutation? Can it change other store values, or should I restrict it to changing only the main value? Because if it is the latter I see a redundancy between mutations and actions, actions could access the store directly instead of reinventing the wheel calling a mutation that triggers the "true" change of state.

Usage with vue-router

It is pretty clear how to use the Vuex with single page app with only one active view.
But how do I manage states in more complex app with different views?
Should I override v-link behavior and run a mutation to change the view?

It would be awesome if you could provide an example for this case, thanks!

Watching for state changes

I was trying to watch for the change of the store, I relied on the very hacky store._vm.$watch. Does it make sense to use this?

If there is no better way to do it, would you accept a PR what exposes $watch in the public API?

Modules states can't be overwritten in their entirety

A couple things at once here, sorry. Hopefully I'm posting this in the correct location, apologies if not – I'm not a seasoned github user.

This is best shown by example. The following code, which is a module in my vuex store, doesn't work as expected (i.e. the changes aren't tracked by vue).

Note: this module is called "comments", the state variable in the mutation is named comments just because that's exactly what it is.

// "comments" module

const state = {};

const mutations = {
    /**
    * Stores the data from an ajax request into the state of comments
    * @param comments [the state variable]
    * @param data [the ajax data from server, an object containing a 'comments' property, which it itself is an object
    **/
    COMMENT_SETDATA (comments, data){
        comments = data.comments;
    },
};

export default {
    state,
    mutations
};

If I were to change this to comments.all = data.comments it would work, but just assigning this top level variable itself doesn't.

[Updated]: Clarified the situation a bit better.

not working on ubuntu 14.10

cd examples/shopping-cart && webpack-dev-server --inline --hot --config ../webpack.shared.config.js

I am trying to test it out. I am running this on ubuntu 14.10 . on running npm install warning is " [email protected] requires a peer of babel-runtime@^5.8.0 but none was installed."

on running : npm run cart

i am getting the following error

events.js:85
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE
at exports._errnoException (util.js:746:11)
at Server._listen2 (net.js:1129:14)
at listen (net.js:1155:10)
at net.js:1253:9
at GetAddrInfoReqWrap.asyncCallback as callback
at GetAddrInfoReqWrap.onlookup as oncomplete

any help please

How to use promise to set initial state data

Hi

I am using NeDB in my project and also vuex. I am having issue to set initial data using promise since nedb returns value inside callback.

So how do we set initial state Data if we have a callback or either using a promise.

How do we handle failure or success of async requests?

Imagine I have a simple login.vue component with a username and password field.

I attempt a login by calling store.actions.login(this.username, this.password)

I want to be able to hide a loading overlay, close the login screen, and provide reasons for login failure.

  1. Should I watch a store.state.isAuthenticated variable and react accordingly?
  2. Should the action be returning a promise?
  3. How can I get a return value on error, so that I can display an error message?

Treat null actions as mutation shorthands

Not sure if I explained myself in the title... For example:

// actions.js
export default {
  addMessage: 'addMessage', // This is the actual, which is OK.
  removeMessage: null, // This is equivalent to removeMessage: 'removeMessage'
};

This would allow to greatly simplify direct actions (at least to me). What do you think?

setTimeout make an error

Uncaught Error: [vuex] Do not mutate vuex store state outside mutation handlers.
use Vuex.createLogger

when I change the state in an setTimeout function in mutation

like this:

import { SET_MSGTIP } from '../mutation-types'

// initial state
// shape: [{ id, quantity }]
const msgTipInitialState = {
    text:''||'😂',
    show:false,
    timer:0
}

// mutations
const msgTipMutations = {
    [SET_MSGTIP]({ msgTip }, text) {
        clearTimeout(msgTip.timer)
        msgTip.text = text
        msgTip.show = true
        msgTip.timer = setTimeout(() => {
            msgTip.show = false
        },2500)
    },
}

export { msgTipInitialState, msgTipMutations }

Is unable to change state in the setTimeout method ?

Mutation not firing in specific cases

Hello,

The problem:
Mutation or otherwise action which fires the mutation does not fire predictably.

The circumstances:
Having:
An input element with @focus and @blur event listeners that trigger the visibility a <div> element on the page.
The <div> contains an <ul> with each <li> having an @click event listener which fires a store action.

Expected behavior when clicking on the <li>
The store action should be called.
The mutation should be fired by the action and change the application state.
The <div> should disappear as the input lost focus on clicking the <li>.

Actual behavior when clicking on the <li>
Sometimes
The store action is not called.
The mutation as a consequence is not fired.
The <div> does disappear as the input lost focus on clicking the <li>.
Sometimes it acts as expected.

Using Vue.nextTick (needlessly) on data change had no effect as expected.
Having the <div> always visible eliminates the problem and actions fire as expected.

Installation issues

The project failed on install for me. After cloning the repos:

$ npm install 

> [email protected] prepublish /Users/xxx/yyy/aaa/bbb/vuex
> babel src --out-dir lib --presets es2015 --plugins add-module-exports

The CLI has been moved into the package `babel-cli`. See http://babeljs.io/docs/usage/cli/

From package.json [scripts]:
"prepublish": "babel src --out-dir lib --presets es2015 --plugins add-module-exports",

This fails with an error ... but works with npm install -g babel babel-cli

Additionally, the index.js file shows:

let Vue

// then in constructor
this._vm = new Vue({
    data: state
})

Generates an error in console at runtime:
Uncaught TypeError: Vue is not a function

Vuex and GraphQL

Hi,

I am very interested in getting vue to work with data coming into the client from a GraphQL server. Would vuex be the place to start working on that? Or would I need to code my own module to support and fill vue with data queried via GraphQL? I'd really like to be able to add GraphQL queries in vue components directly, similar to how it is done with React.

Thanks for any help on a proper direction.

Scott

Vuex + vue-webpack-boilerplate (Uncaught TypeError: Vue is not a function)

I am getting this error:

Uncaught TypeError: Vue is not a function

At this specific line: https://github.com/vuejs/vuex/blob/master/src/index.js#L32

I am using the webpack template.

I was able to reproduce the issue applying these minimal changes to the initial template:
https://github.com/jbruni/vuex-webpack-issue/commit/50af38cfbb94dc27a6d48082d0e7ecd6d0650366

Please, take a look... I believe the solution for this issue is very simple.

(I was not sure if I should open the issue at webpack template repo or here. It seems a Vuex issue to me, so I opened here. Thank you.)

Note: the same error happens both using npm run dev as well as building with npm run build and HTTP serving the static build.

Mixing multiple submodule actions

As i've understood the concept all our actions have to be merged in one object.

So what with action's name isolation (namespaces) when i'm using one store with many submodule actions?

Browser history doesn't work in todomvc example?

Is browser history supposed to work properly in the todomvc example as it currently stands? Because it doesn't seem to. Or would fully functioning browser history require integrating vue-router, or something else entirely?

Getting warn for props from global mixin

As the title suggests, vuex harshly handles global props.

When doing

new Vuex.Store({
    state,
    mutations
})

I get the following warning:

[Vue warn]: Props will not be compiled if no `el` option is provided at instantiation.

And I have a global mixin with props defined like this:

Vue.mixin({
    props: {
        id: {},
    }
})

Stacktrace kindly pins the origin of issue:

// use a Vue instance to store the state tree
this._vm = new Vue({
  data: state
});

Any information on the subject is much appreciated.

Shared getters should only execute once even if used by multiple components

I have an computed property that is expensive to process, and is used in many different components. Using a shared getter as described in http://vuex.vuejs.org/en/state.html works, but the getter gets called once for every instance of the component, even though it's returning the same data.

The only way I can think of doing this with the existing functionality is to manually set a watch on the relevant data, then dispatch a mutation when it changes to update a property in the state object... or just put a getter in a parent component and pass the data down as a prop. In my case I ended up going with the latter, but I would think there should be an easier way. Thoughts?

API change ideas

Some breaking changes currently being considered.

Usage in components

Currently, all components that need to display store state or invoke store actions import the store directly. This makes the component definitions rely on a global singleton, and leads to the following drawbacks:

  1. A bit harder to test: the store needs to be mocked in order to test the component in isolation.
  2. Makes server side rendering hard, because ideally we want a fresh store instance for each request.

So the first thing we can do, is instead of directly importing the store in child components, we only import it at the root component and "inject" it into all child components:

// Vue.use(Vuex) teaches Vue instances to handle the `store` option
import store from '../store'
import App from '../components/App.vue'

// render root
new Vue({
  el: '#app',
  store, // provide store, and inject to all children
  components: { App }
})

Now, the store will automatically be available to all children as this.$store (similar to how this.$router is injected to all components enabled by vue-router). However, this makes things a bit more verbose and repetitive:

// example component after the change
export default {
  computed: {
    someState () {
      return this.$store.state.someState
    },
    computedState () {
      const { valueA, valueB } = this.$store.state
      return valueA + valueB
    }
  },
  methods: {
    someAction (...args) {
      this.$store.actions.someAction(...args)
    }
  }
}

So, the idea is introducing a vuex option:

import { someAction } from '../store/actions'

export default {
  vuex: {
    state: {
      someState: state => state.someState,
      computedState: ({ valueA, valueB }) => valueA + valueB
    },
    actions: {
      someAction, // becomes available as a method `this.someAction`
      // ad-hoc inline action
      inlineAction: ({ dispatch }, ...args) => dispatch('SOME_MUTATION', ...args)
    }
  }
}

Note what's happening here:

  1. vuex.state is basically sugar for computed properties. The difference is that the getters will get passed the store's state as the argument.
  2. vuex.actions is sugar for mapping actions to methods. Note **we are no longer exposing the actions on the store itself. Now the store is only concerned with state and mutations. Actions are simply functions that take store as the first argument and dispatch mutations on it. What the vuex.actions option does, is essentially binding raw action functions to this.$store, and then defining it as a directly callable method on the component. Here we are using the Object literal shorthand, so the method name will be the same (someAction). You can of course use a method name different from the imported function.

Now, why do we no longer expose actions on the store? Several reasons:

  1. Users have been asking about how to "namespace" the actions, because all actions share the same namespace on store.actions. By directly importing actions where needed, this problem no longer exists.
  2. This allows you to see where the action functions are defined right inside the component, thus allowing more flexibility in where to place them (instead of all inside a single actions.js file). For example you can split them up into store modules, and don't need to worry about not knowing which module an action is defined in.

Because actions are defined without directly depending on the store (instead takes it as an argument), importing them doesn't cause the singleton problem. When they are bound by vuex.actions internally, they just use whatever store the component has.

Module composition

Currently, module composition is a bit awkward:

import * as moduleA from './modules/a'
import * as moduleB from './modules/b'

export default new Vuex.Store({
  state: {
    a: moduleA.state,
    b: moduleB.state
  },
  mutations: [moduleA.mutations, moduleB.mutations]
})

This can get annoying when there are many modules. Also, mutations inside modules always get the whole state tree. This leads to:

  1. A module's mutation can actually mutate sub trees managed by other modules;
  2. A module's mutation needs knowledge of how modules are composed in order to "resolve" the sub tree it owns. This makes it hard to develop decoupled store modules.

Here's an idea for a better composition API:

// a module
const state = {
  count: 0
}

const mutations = {
  INCREMENT: state => state.count++, // receives only the sub tree owned by this module
  DECREMENT: state => state.count--
}

export default {
  state,
  mutations
}
// composing modules
import counter from './modules/counter'

const inlineModule =  {
  state: { n: 123 },
  mutations: { INCREMENT: state => state.n++ }
}

export default new Vuex.Store({
  state, // global state...
  mutations, // global mutations...
  modules: {
    counter, // adds and manages `store.state.counter`
    inline: inlineModule
  }
})

So modules essentially become "sub stores" that manages a sub tree of the state.

Unresolved questions

Actions still get the entire store. Which means if an action is shipped within a module, it has no way to know how to resolve its local state.

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.