Correct place to run script in vuex flow? - vue.js

I have an action, setProducts, which I'm passing a payload which returned from a productSearch() method.
In my Vue component this looks as follows:
let products = productSearch();
this.$store.dispatch('setProducts', products);
However, I'm wondering if the correct way to do this would be to refactor my setProducts action to searchProducts then in my mutator call the productSearch() method.
So from my component I run:
this.$store.dispatch('searchProducts');
Then for my mutator method I'd have something like this:
searchProducts(state) {
state.products = productSearch();
},
Is there a more "correct" way to do this?

I think it would be better like this:
Component:
this.$store.dispatch('searchProducts')
Action:
searchProducts(state) {
commit('updateProducts', productSearch())'
}
Mutator:
updateProducts(state, products) {
state.products = products
}
Actions shouldn't directly affect state's values.
You always need to use commit and mutators to update your store variables, and your mutators should never call functions, they work like setters (receive a variable as paramater and apply it to the state variable).

Related

sub-property write commit withing store actions using vuex-pathify make.mutations

Here is how my store looks like:
const state = {
user: {
profile: {
phoneNumber: '',
}
}
}
const mutations = make.mutations(state)
const actions = {
submitPhoneNumber({commit}, phone_number) {
// blah blah
commit('SET_USER#profile.phoneNumber', phone_number);
}
}
But no such mutation can be found.
Maybe I could import store.js within store.js and use the set helper but I believe things can get pretty creepy specially because of the (In my opinion poor) design decision that the library creator has made to combine commit and dispatch (I believe being explicit would have been much better here)
Pathify author here.
You can't commit a mutation with sub-property syntax using Vuex mutations, because Vuex will treat it as a string.
You are correct that you would need to use store.set() to do this.
You can be explicit with commits and dispatches by appending a ! to the call. This is called "direct syntax":
https://davestewart.github.io/vuex-pathify/#/api/paths?id=direct-syntax
To commit directly using the sub-property syntax, use the Payload class:
https://github.com/davestewart/vuex-pathify/blob/master/src/classes/Payload.js
https://davestewart.github.io/vuex-pathify/#/api/properties?id=payload-class
Something like this should work:
import { Payload } from 'vuex-pathify'
commit('SET_USER', new Payload('SET_USER', #profile.phoneNumber', phone_number);
Looks like I haven't documented this, so I have a made a ticket here:
https://github.com/davestewart/vuex-pathify/issues/80
It's using a commit from a component, but should work just the same.
People have asked before if it would be possible to use Pathify-style commits in actions and I said it wasn't, but I've just thought of something that might make it possible.
Follow this feature request for more info:
https://github.com/davestewart/vuex-pathify/issues/79

Why should I use the action decorator in mobx

I'm trying to get my head around the usefulness of the action decorator in mobx, even after reading the doc, https://mobx.js.org/refguide/action.html
Still wondering why I should use #action or #action.bound, other than to enforce a pattern where a component cannot change the observable directly.
The above article mentions providing "useful debugging information". But where can I find this info? F12->Console doesn't show anything when calling an #action or #action.bound method.
Or am I doing something wrong in the below code?
Should I install some mobx debugger? Thanks.
class CommentStore {
#observable commentData = [];
#action.bound
updateComment(id, name) {
this.commentData.map(p => p.id === id ? p.name = name : p.name = p.name);
}
...
If you mutate more than an observable variables inside a method which is not decorated by #action, your derivations (autorun) will run multiple time. This issue is not present when you work with react. render function will run only once.
one of the things which #action decorator do is to prevent multiple invocation of your derivations.

How to call a shared helper function from within a mutation or action in Vuex

I am trying to separate out some code that is common among many calls in my Vuex mutations. I am getting the feeling that this is discouraged but I don't understand why.
Have a look at an image of some sample code below:
I have added this 'helpers' entry in the Vuex - this obviously doesn't exist but how can I call the shared helper function 'getColumn' from mutations and/or actions?
Or do I have resort to calling a static method on a 'VuexHelper' class? :(
Something like:
Note
I have already looked at the following:
Vue Mixins - yes, something like that could work but is not
supported in Vuex - also, vue methods don't return a value...
I have looked at Modules but these still don't give me what I need, i.e. a simple re-usable function that returns a value.
Thanks
I don't see why you may want to put the helper function within the store. You can just use a plain function.
function getColumn(state, colName) {
// Do your thing.
}
const vstore = new Vuex.Store({
// ....
mutations: {
removeColumn(state, colName) {
var column = getColumns(state, colName);
}
}
};
On the other hand, if you really need that, you can access the raw module and all that's included:
var column = this._modules.root._rawModule.helpers.getColumns(state, colName);
Although this syntax is not documented and can change for later versions.
You can implement your Vuex getter as a method-style getter. This lets you pass in the specific column as an argument:
getters: {
getColumn: state => colName => {
return state.columns[colName] || null
}
}
Then getColumn can be used within the store like so:
let column = getters.getColumn('colNameString')
vuex docs > getters > method style access

Return value from vuex mutation? (id for newly created object)

I'm trying to create an object in one part of vuex store, and then pass id to it to another object, and i'm not sure how to properly do that since mutations can't return returning anything (in this case, id).
Two store objects look like this:
// store/report.js
const state = {
name: 'Untitled Report',
subReportIds: []
};
// store/subReport.js
const state = { ... }
And i'd like this action to create blank report, then blank subreport, and then assign subreport id to newly created report. (subreports are independent entities, and can be used by multiple reports, hence different area in store)
const actions = {
createNewReport({ state, commit }) {
commit(mutationTypes.CREATE_NEW_REPORT)
// below doesn't work - i can't get return from mutation
let newSubreportId = commit(mutationTypes.ADD_NEW_SUBREPORT)
// if this worked, i'd then do something like
commit(mutationTypes.ADD_SUBREPORT_TO_REPORT, newSubreportId)
}
};
How can i achieve the above?
So best way to accomplish to me would be to dispatch actions instead of committing the mutations. If you look at the methods in Vuex source, commit only executes with no return (so is a void) and dispatch returns the value you return from the action (which is a function)
For my actions, i always return a promise so that i can compose them like you mention above. Here is an example.
fetchSomething ({ commit }) {
return mockApiGetIds()
.then(response => {
commit({
type: SOME_MUTATION,
ids: response
});
return response;
});
},
Disclaimer : I don't know if it is truely a good idea, but at least, it seems to work, and to me, it feels prettier than having to use actions and promises, or to generate the id in the action...
With your mutation, you can pass an argument. To return a value from a mutation (like a newly created id), I write it to a placeholder in that argument :
someMutation(state, arg){
//...
arg.out = {
status : "succeed"
}
}
//...
this.$store.commit('someMutation', arg);
if(arg.out !== "succeed") console.log("ERROR");

Callback on transaction or commit()

How can I achieve something similar like that?
App.saveManyDifferentModels()
App.store.commit(function() {
$("#spinner.gif").hide()
});
There is no generic hook at that moment on the transaction that would allow that.
However, if you are persisting a single record, you could add use the didCreate or didUpdate hook on the model.
Another option could be to handle that while changing state/route on the app.
Actually there is a way to do this. For example in your controller you can add a 'didUpdate' method to your model, like this:
var post = this.get("model");
post.didUpdate = function() {
$("#spinner.gif").hide();
};
this.get("store").commit();