Automatic object mutation Vuejs - vue.js

I have a little problem.
I'm working with Vuex and I have a "user" status of object type that when I call this from my component and assign it to the model that I have everything works fine, but when making a change in the model I automatically mutate to my been "user", which I do not want this to happen.enter image description here

You can connect vuex state to v-model with computed's set and get.
In the get you should write a function that returns the desired data from the store.
In the set you should write a function that commits a mutation to the store.
vuex docs encourage deveolopers to handle forms this way.
{
template : '<input v-model="username"',
computed: {
username: {
get: function () {return this.$store.user.name},
set: function (newVal) { this.$store.commit('setNewName', newVal)}
}
}
}

Related

vue - changing localstate triggers vuex error

Whenever i update local state, vuex throws error [vuex] do not mutate vuex store state outside mutation handlers. even though I am not even trying to change vuex store. What is the problem?
data: {
selected: []
},
methods: {
addItem(item){
this.selected.push({
name: item.name,
count: item.count
})
},
applySelected(){
this.$store.dispatch('changeItems', this.selected)
}
}
<button #click="item.count++"/>
<span>{{item.count}}</span>
<button #click="item.count--"/>
items are in loop but proper markup and surrounding code is unnecessary for that example.
Now when selected[] is empty, when i do addItem(item) it works fine. Then when i change count, it still works just fine. When i commit changed to the store, guess what - it still works fine. But when i try to change count after it was submitted to the store, even though i have 0 getters, not reading store at all, don't have any additional mutation/dispatch calls, whenever i try to change count of selected[] items, it throws vuex error. but why?
it doesnt make any sense to change vuex state in component. its better to change it via a mutation.
but there is a way to solve this locally and you have to call a function that returns new object of items in vuex store. maybe like this:
computed: {
selected() {
return () => this.$store.state.selected
}
}

vuex: do not mutate vuex store state outside mutation

I have the following scenario:
Component Textfield:
<v-text-field
v-model="form.profile.mobile_business"
label="Mobile"
prepend-inner-icon="mdi-cellphone"
></v-text-field>
I get the current value via:
data() {
return {
form: {
profile: JSON.parse(JSON.stringify(this.$store.getters["user/Profile"])),
},
};
},
I have a submit button that calls this method:
updateUserProfile() {
this.$store.dispatch("user/updateProfile", this.form.profile);
}
Everything works perfect. On my store dispatch I make the API call and update the store via my mutation:
context.commit('UPDATE_PROFILE', profile);
No errors until this step.
But if I change the form input again - after I pressed the submit button, I get:
vuex: do not mutate vuex store state outside mutation
But I don't want to change the vuex store just when I change the value on my form input.
It should only be updated if someone hits the submit button.
v-model provides 2-way data binding. Changing anything in the view will automatically attempt to update the model directly, rather than through a mutation. Thankfully, Vue allows get and set on computed properties to help us past that.
What you should do on your textfield component is add a computed property with get and set methods. It will look something like this:
computed: {
userProfile: {
get() {
JSON.parse(JSON.stringify(this.$store.getters["user/Profile"]));
},
set() {
// only commit the changes to the form, do not submit the action that calls the API here.
this.$store.commit("user/updateProfile", this.form.profile)
}
}
Your v-model attribute should then be set to this newly created property, and any 'set' operations (read: a user changing the input value) will call the action as opposed to attempting to set the value in the Store directly.
Here is a live example: CodePen
I solved it this way:
form: {
profile: _.cloneDeep(this.$store.getters['user/Profile'])
},
and added a watch handler:
form: {
handler: _.debounce(function (form) {
console.log("watch fired");
}, 500), deep: true
}
so if the user changes the value, nothing happens (except my console.log action).
if he presses the submit button, the store dispatch action will be fired.

update my for loop when results when state changes in a vuex store

I have a list of todos that I'd like to watch and auto update when a change is made in a firebase backend
Got a bit stuck on what i hope is the last step (I am using nuxtjs for a SPA)
I have a getter in my vuex store as follows
getMyState: state => {
return state.todos
}
I am returning this getter to my component as follows
computed: {
...mapGetters(['getMyState'])
},
How do i now get my list to recognise when something has changed and update my array of results?
Thanks
Use watch property
watch: {
getMyState: function (new, old) {
}
},

vuejs vuex use state in two way binding without mutation (v-model)

I know that I am supposed to use mutations to change state. However I was wondering if it is theoretivally possible to use state in a v-model binding.
My current solution:
html:
...
<input v-model='todo'>
...
with mutation:
...
computed: {
todo: {
get () { return this.$store.state.todos.todo },
set (value) { this.$store.commit('updateTodo', value) }
}
}
...
without mutation
...
computed: {
todo: {
get () { return this.$store.state.todos.todo },
set (value) { this.$store.state.todos.todo = value }
}
}
...
what I would like:
...
<input v-model='this.$store.state.todos.todo'>
...
You can directly bind a Vuex state property to a component or input via v-model:
<input v-model='$store.state.todos.todo'>
But this is strongly recommended against. Vuex will warn you that you are mutating the state outside of a mutation function.
Since, when using Vuex, your state object is your source of truth which is designed to only be updated in a mutation function, it will quickly become hard to debug why the global state is changing if one component is affecting the global state without calling a mutation.
Most people, I believe, would recommend using your computed todo property example with mutations for the scenario you're describing.

Emit an event when a specific piece of state changes in vuex store

I have a Vuex store with the following state:
state: {
authed: false,
id: false
}
Inside a component I want to watch for changes to the authed state and send an AJAX call to the server. It needs to be done in various components.
I tried using store.watch(), but that fires when either id or authed changes. I also noticed, it's different from vm.$watch in that you can't specify a property. When i tried to do this:
store.watch('authed', function(newValue, oldValue){
//some code
});
I got this error:
[vuex] store.watch only accepts a function.
Any help is appreciated!
Just set a getter for the authed state in your component and watch that local getter:
watch: {
'authed': function () {
...
}
}
Or you can use ...
let suscribe = store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
// call suscribe() for unsuscribe
https://vuex.vuejs.org/api/#subscribe