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
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
}
}
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.
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) {
}
},
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.
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