Hi, thanks for your work. Vue & Vuex are really awesome. I was wondering is there any way of commiting multiple mutations at once, passing them as array of objects?
Current code:
commit('LOADING', false)
...
(many commits go here)
What I was looking for is smth like this:
commit([
{
type: 'LOADING',
payload: false
},
...
])
Looking forward to your reply about this small issue :)
I like the idea. Also we can compose multiple actions with returned promises.
// current
Promise.all([
dispatch('FETCH_FOO')
dispatch('FETCH_BAR')
dispatch('FETCH_BAZ')
]).then(() => { /* ... */ })
// passing array
dispatch([
{ type: 'FETCH_FOO' },
{ type: 'FETCH_BAR' },
{ type: 'FETCH_BAZ' }
]).then(() => { /* ... */ })
So I'm not on Vuex core team but am a user of it.
Just from my perspective, this doesn't seem like something that needs to be in vuex b/c it can easily be handled in userland.
This seems like it would make more sense for actions (which ktsn is demonstrating) than mutations (which OP is asking for) because actions can return promises. Even then I agree with Austio.
IMHO, it's worth adding if the use case is well common and the users always write such helpers to achieve it. Isn't it common pattern to commit/dispatch batched mutations/actions?
Chiming in on this - I have many situations like the OP described, where I do multiple dispatches and wait for them all to resolve before mutating the state. This kind of functionality would be very nice!
I really think it's not worth adding because in the code you showed:
// current
Promise.all([
dispatch('FETCH_FOO'),
dispatch('FETCH_BAR'),
dispatch('FETCH_BAZ')
]).then(() => { /* ... */ })
// passing array
dispatch([
{ type: 'FETCH_FOO' },
{ type: 'FETCH_BAR' },
{ type: 'FETCH_BAZ' }
]).then(() => { /* ... */ })
The first version is explicitly telling you the strategy used for the promise and is pure js so it's knowledge you can reuse elsewhere. The size difference is too small. Also, if I want to add a fetch in the middle of the promise.all, it's much easier with the first solution:
// current
Promise.all([
dispatch('FETCH_FOO'),
dispatch('FETCH_BAR'),
dispatch('FETCH_BAZ'),
fetchData()
]).then(() => { /* ... */ })
// passing array
Promise.all([
fetchData(),
dispatch([
{ type: 'FETCH_FOO' },
{ type: 'FETCH_BAR' },
{ type: 'FETCH_BAZ' }
])
]).then(() => { /* ... */ })
The original proposal was about mutations and presumably the idea is that all the mutations would show up as a single commit in the dev tools / history browser? At least that's something I just wondered about.
('commit' somehow suggests the availability of transactions. But I'm very new to this and maybe I got this wrong ;-)
Hi, thanks for this great project 👍
I have been using state persistence with localStorage, but had some problems with the limit, then I found vuex-persist which allows to have async methods in the storage, a bit tricky to integrate with the event 'storageReady' but anyway the problem is that with several commits in one action, each commit will trigger a different state-change/state-save which is very noticeable using async persistence.
https://github.com/vuejs/vuex/issues/1109#issuecomment-355054546
BTW, it may be an off topic but I feel it would be better to use action type constants rather than mutation types because actions are used from different places than mutations - actions are usually called from components but mutations are called from actions in the same module.
Perhaps actions should trigger the state changes instead? or have a transaction method like @helje5 mentioned? anyhow using the plugin above I was able to solve the issue using the filter configuration, which worked nicely to prevent extra state saves with several commits 😄 hope that this helps anyone facing a similar issue, and sorry if it's a bit off topic.
I have a similar use case that needs this feature. That's say I have an action will go fetch data via an API gateway, the API gateway hidden many business logic and will give me well-structured resources all at once. Then I normalize the data by grouping them by their types. I have also used the namespaces modules based on the type. Now I want to distribute these resources by committing them into their corresponding store module state. My current implementations just using multiple commits in the handler. I wonder if I can batch my commits thus avoid some problems and perhaps save some resources, especially in the mobile condition.
Some kind of transactions is neccessary because each mutation recalculates entire application: getters, $store-based reactivity etc.
So, if I am loading many items from database, it seems more efficient to temporary save them into array and then commit mutation like bulkAddItems(state, itemsArray) rather than addItem(state, item) for every entry. It is ok to write separated action for complex logic, but architectural principles of Vuex, I think, are trying to avoid creation separated non-atomic mutations for this.
It will be cool to have something like this:
```
Store.beginTransaction(); // disables recalculating after mutation
commit...
commit...
Store.endTransaction();
Some kind of transactions is neccessary because each mutation recalculates entire application: getters, $store-based reactivity etc.
So, if I am loading many items from database, it seems more efficient to temporary save them into array and then commit mutation like
bulkAddItems(state, itemsArray)rather thanaddItem(state, item)for every entry. It is ok to write separated action for complex logic, but architectural principles of Vuex, I think, are trying to avoid creation separated non-atomic mutations for this.It will be cool to have something like this:
Store.beginTransaction(); // disables recalculating after mutation commit... commit... Store.endTransaction();
Here's an idea
const mutations = {
...
applyCommits(state: CartState, commits) {
commits.forEach( (args, fnName) => mutations[fnName].apply(this, [state, ...(args || [])]))
}
}
...
const actions = {
batchDoSomething() {
// use a es6 map to ensure insertion order, so commits go in order
commit('applyCommits', new Map().set('myMutation', [arg1]).set('myOtherMutation', null))
}
}
Do not reinvent the bike. It is not necessary to burden the library with the functions that can be replaced by pure JS. If you really have a lot of commits, why not just do something similar
[
{
type: 'LOADING',
payload: false
},
...
].map(opt => commit(opt))
@cawa-93 I think we are talking about debounce for recalculate subscribers
Необходим некоторый тип транзакций, потому что каждая мутация пересчитывает все приложение: геттеры, реактивность на основе $ store и т. Д.
Поэтому, если я загружаю много элементов из базы данных, кажется более эффективным временно сохранить их в массив и затем зафиксировать мутацию,
bulkAddItems(state, itemsArray)а неaddItem(state, item)для каждой записи. Можно написать отдельное действие для сложной логики, но архитектурные принципы Vuex, я думаю, пытаются избежать создания отдельных неатомных мутаций для этого.Будет круто иметь что-то вроде этого:
Store.beginTransaction(); // disables recalculating after mutation commit... commit... Store.endTransaction();
this would help to make fast timetravel without comparison state and mutation
According to the reactions on this thread and since this can be easily achievable without modifying Vuex, I guess this is not worth adding into Vuex. Thank you for your feedbacks!
The proposed solutions are either an Array.map() or a Promise.all() of single commits.
We need a solution to commit multiple values.
Or maybe I did not understood the solution to avoid each mutation to refresh the application.
Indeed, for my project a batch of mutations or a way of disabling reactivity would be highly necessary.
We're calling multiple mutations that have many getters, and when changing pages you can clearly see for a second all the components disappearing while the new state reaches to the page, instead of blinking all at once which in this case would be the better UX.
The OP was referring to grouping mutations, not actions, with the goal of reducing multiple reactivity updates within a short period of time by either something like a debounce or a way to group multiple mutations into one (without having to manually write one mutation that specifically does the X mutations we're trying to group).
This should be reopened.
Vuex authors, thank you for the library and having that conversation!
Agree with the comments after the thread was closed. This is not just syntactic sugar.
Each commit/mutation does a lot of stuff (somebody mentioned flickering for example). A commit modifies state and the state is then written to local storage. If you use vuex-persistedstate, then also encrypted. Run multiple commits - get multiple writes (and encryptions).
IMHO, it makes total sense to batch multiple commits at once.
Most helpful comment
Some kind of transactions is neccessary because each mutation recalculates entire application: getters, $store-based reactivity etc.
So, if I am loading many items from database, it seems more efficient to temporary save them into array and then commit mutation like
bulkAddItems(state, itemsArray)rather thanaddItem(state, item)for every entry. It is ok to write separated action for complex logic, but architectural principles of Vuex, I think, are trying to avoid creation separated non-atomic mutations for this.It will be cool to have something like this:
```
Store.beginTransaction(); // disables recalculating after mutation
commit...
commit...
Store.endTransaction();