Vuex vs Simple Shared Data - vue.js

Is there anything Vuex can do that the following simple shared store can not? --
let store = {
user: {
name: 'John Doe'
}
};
new Vue({
el: '#app-one',
data: {
bar: 'foo',
shared: store
}
});
new Vue({
el: '#app-two',
data: {
foo: 'bar',
shared: store
}
});
If so, what are those common use cases?

Deep down, a Vuex store is just a Vue reactive object as the one you are adding.
So if you would only use the state of the Vuex store via direct access, then the two approaches work the same.
The thing is, if, in Vuex, you are using only the state directly, you are pretty much underusing the tool. You are paying the price, but not reaping the benefits.
Vuex has getters, which are like reusable computed properties. They also allow you to decouple your apps from the inner structure of the store's state.
Vuex has modules/namespaces, which allow you to break down your store code and better organize it as it grows.
Vuex also have actions and mutations. Actions allow you to create "methods" that are reusable by any Vue instance (or component) that uses the store. Another important thing is actions and mutations enforce a "protocol" that will also help you to better organize your code and, most importantly of all: will help you debug your code more easily when things get troublesome (and they will, if your app grows enough).
For one example, consider an app which many points of the app change the same bit of state. Consider also that some of these changes are done asynchronously. Using Vuex, you know that any async operation is being done within actions, so if you have any "race" problem, the source of the issue must be there. In Vuex, you also know that, ultimately, the changes to the state are made at mutations only (and synchronously). So if things get crazy, you can always place a breakpoint at that mutation and find out what the heck is invoking it. If you don't use Vuex, in any reasonably big app, the changes will come from too many places at too many rates, making your life not so easy after all.

Related

What is the best practice for multiple trivial mutations in Vuex store?

In my Vuex code, I have countless trivial mutations, like:
setOption(state, payload) {
state.option = payload;
}
With hundreds of similar lines of code, it doesn't look to be good. Any better option?
Option 0 (New Recommended)
Consider switching to Pinia, new official state manager for Vue.
Mutations do not exist any more. These can be converted to actions instead, or you can just assign directly to the store within your components (eg. userStore.firstName = 'FirstName')
Option 1 (Old Recommended)
Keep it this way.
Pros:
Standard, well-documented.
IDE support. You can easily find usages of some mutation across your project.
Easy to add more logic when needed, e.g. age should be a positive number, etc...
Cons:
Might look repetitive, so it is easier to skip some non-trivial mutation. However, this can partly be solved by convention to put all trivial to the end of the file\section, as soon as mutation stops to be non-trivial - move it to the top of the file\section.
Option 2
Use a universal mutation :
mutate(state, payload) {
state[payload.property] = payload.with;
}
and call it:
commit('mutate', {
property: <propertyNameHere>,
with: <valueGoesHere>
});
Pros:
Clean mutation section, non-trivial mutations are visually distinct.
Cons:
A little harder to find related mutations, e.g. some can have two or more spaces after property:
More writing for each mutation call.
Not really compatible with a standard way, so you can end with non-trivial mutation with additional logic, but someone can miss it and use a unified mutation call.
Option 3
Use some code generator, e.g. Hygen
Pros:
You have the same code as from Option 1, including IDE support and future extension.
You can set it to add in all places by a single command line - to state, mutation, and action (if needed).
With typescript you also need to change interface of the store, wich can also be done with the same command line.
Cons:
Can be hard to set up.
Need additional informing of new team members.
Option 4
Use some Vuex plugin with predefined mutations, e.g. this one
Pros:
Minimal setup.
Clean mutation section, non-trivial mutations are visually distinct.
Cons:
Needs some knowledge about the plugin.
A little harder to find related mutations
Not really compatible with a standard way, so you can end with non-trivial mutation with additional logic, but someone can miss it and use a mutation call provided by a plugin.

Why should I use getters and mutations instead if getting/setting value direct?

What is the difference between:
this.currentLanguage = this.$store.getters.currentLanguage;
and this for getters:
this.currentLanguage = this.$store.state.currentLanguage;
Also this:
this.$store.commit('setLanguages', this.languages);
is gives me same results with this in mutations :
this.$store.state.languages = this.languages;
I'm receiving what I want in both cases. And getting value direct is easier because I don't need to write getter/mutation.
Why should I use getters/mutations?
you do not need to use getters in this case. getters are like computed properties on a regular Vue component, so you only need them when the data is a more complex descendant of the other data.
you want to use mutations, however, because even if it looks like the this.$store.state.languages = this.languages is working, it isn't necessarily updating it correctly. if you have other components depending on the store, it may not receive the new data because it hasn't undergone the full mutation process.
When you use mutations you have a clear record of what changed in things like vue-devtools. It also allows for time travel debugging.
This is really nice when you're debugging.
The state vs getters is a lot more of a gray area. I personally like not having to think if something is in state or a getter. If I need to get something from the store I use a getter.
That question got answered pretty well by the Vuex Docs itself:
Again, the reason we are committing a mutation instead of changing store.state.count directly, is because we want to explicitly track it. This simple convention makes your intention more explicit, so that you can reason about state changes in your app better when reading the code. In addition, this gives us the opportunity to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging. https://vuex.vuejs.org/guide/ - nearly bottom
So basically the idea is to explicitly track changes. This allows other tools to attach themself to those mutations and actions and track your code which is a huge benefit for large scale applications. It will also make your code more readable and at a later stage much easier to update. Ever read into an old project where they always changed on the go without one "way" to do it - it won't happen here.

shoud I use vuex getters even when no computation is involved?

If i just want to return a member of my vuex state, should I define a getter for it? or is it o.k. to use mapState ?
My dilemma is as follows:
1) It seems redundent to have a getter that simply returns a member of the state as in:
getters: {
user (state) {
return state.user
}
}
when I can just use the following code in the consuming component and save the coding of the getter ?
computed: {
...mapState('auth',['user']),
}
However, if something did change in the future and I would like some computation done on the user object before it is returned then using a getter and
computed: {
...mapGetters('auth',['user']),
}
Would allow for a simpler change.
But if this is the recommended way to go then why provide mapState to begin with?
So should I use getters for this type of simple state memeber access? or not?
Technically, as you note, you can do either way. When there's no calculation involved, though, it becomes a matter of taste.
There's no authority in this, but I'd recommend as general advice:
If your application...
has a stablished state format AND
your state that doesn't tend to change AND
your application is not that big,
...then map to state.
Else, use getters.
In other words, if your application is somewhat small and should be stable, then, why not?
If else, other than the obvious "use getters when you need calculations", if your application:
tends to grow OR
has a state structure that is not stablished and tends to change OR
has deeply nested state.
Then use getters. They decouple you application from the state, allowing it to change more freely (which is frequently
needed "in times of trouble"), simplifying refactoring a lot.
In other words,
when in doubt, use getters instead of mapping directly to state.
Note: IMO, this question is the same as using Selectors in Redux. And, in Redux, the usage of selectors is widely recommended.

Should a component commit a mutation directly?

In the Mutations chapter, you can see an example that uses mapMutations to map mutations to component methods.
It also says that
You can commit mutations in components with this.$store.commit('xxx')
So the question comes, is committing a mutation directly from a component (not through an action) fine in vuex?
If it is, then this diagram may need to update:
Should I keep using the mapMutations method?
As far as I understood, actions are mainly used for asynchronous operations which might comprise multiple mutations. So yes, it's ok to directly use mutations, that's what they are made for. Only when you have more complex workflows involving multiple mutations you should wrap them in an action.
MapMuation is just a helper that lets you use your defined mutations (in mutation-types) as methods of your component. It is exactly the same with $store.commit but with an easier notation.
I don't know in which context your diagram is but mutations can be called from everywhere (components, services, actions, getters etc...) en will do its work finely by synchronously updating the store.

Performance impact of stacking multiple Vue components

I am building an application that uses Vue to display most of the data that my users will see (charts, tables, etc.)
Now, imagine I have a table built with Vue with a list of actions performed by each user. Now, the user name cell will be especially formatted with the user’s picture, social handle, etc. The way the user is presented in this table is the same as it will be in other components. It will also contain some especific functionality (e.g. hovering over the picture will provide expanded information about the user; but this functionality is only planned).
My objective is to reuse as much code as possible. This is why I was planning to have a small UserProfile.vue component inside my Table.vue component. Using this logic, I may repeat this for other information as well (think CompanyProfile.vue, ProjectDetail.vue, etc.).
Is this a good idea? Will it have cause significant performance issues to have multiple vue components inside one and other?
Vue has optimized the result of rendered html as far as possible. You don't need to worry a lot about it. Child components only update when their respective data has changed, that is usually quite cheap.
Good to keep in mind:
When authoring components, it’s good to keep in mind whether you intend to reuse it somewhere else later. It’s OK for one-off components to be tightly coupled, but reusable components should define a clean public interface and make no assumptions about the context it’s used in.
For larger applications, you may use Async Components
Vue will only trigger the factory function when the component actually needs to be rendered and will cache the result for future re-renders. For example:
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// Pass the component definition to the resolve callback
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
I found some interesting topics that you might want to look:
Performance for large number of components
Performance degradation when using components
Unlock performance tracing in vue
Analyze runtime performance
So now, you know what to do. Hope, it helps.