Vuex State - Array empty - vue.js

My Problem is, that the state-variable "genreRankings" in "store.js" is never updating.
Can somebody tell me why?
I'm accessing the Store via my Component as follows:
saveMovie (item) {
this.$store.dispatch('addMovie', item).then(x => {
console.log(this.$store.state.savedMovies)
this.$store.commit('update_genreRankings', Util.getGenreRankings(this.$store.getters.savedMovies))
})
},
removeMovie (item) {
this.$store.dispatch('removeMovie', item).then(x => {
this.$store.commit('update_genreRankings', Util.getGenreRankings(this.$store.getters.savedMovies))
})
},
Here is store.js (https://gist.github.com/oaltena/ccc70c06c29a1d9af6aa3234aba79518) and Util.js (https://gist.github.com/oaltena/67b8431199e9a6d74681c04d9183e630).
When i access the "genreRankings" via VueDevTools the array is always empty.
Help, please! :-)

Try "replacing" the state with a new array :
state.savedMovies = state.savedMovies.concat(object)
As written in the Vuex documentation, the state of Vuex store follows the same rules as the state in the components : https://vuex.vuejs.org/guide/mutations.html#mutations-follow-vue-s-reactivity-rules
PS: it's pretty ugly to call mutations directly from the components, use mapActions to map your actions in your components, then call commit from the action. You'll make a more maintenable code.

Try replacing this:
update_genreRankings (state, object) {
state.genreRankings = object
}
with this:
update_genreRankings (state, object) {
Vue.set(state, 'genreRankings', object)
}
Reference: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

Related

What is the correct way to deep clone / unbind a object in Vuex

I'm constantly getting the "[vuex] do not mutate vuex store state outside mutation handlers." error on my application. When I use a getter inside a component, I solve it destructuring the getter, something like:
const user = {
...this.$store.getters["Users/getUser"]
};
But sometimes, when I need to use something of my store state, inside a Vuex action, the only wat to "unbind" the object is using JSON.parse(JSON.stringify(state.something)), because destructuring still returns Vuex mutation error, and using the JSON.stringify and JSON.parse is probably the wrong way:
setActiveUser({ commit, state }, payload) {
return new Promise((resolve, reject) => {
let newUser = JSON.parse(JSON.parse(state.user))
etc
});
}
What is the correct way to unbind my state?
Thank you.

How to empty a Vuex store module state object?

How to empty a Vuex store module state object completely? I know how to delete a single property of state object for e.g Vue.delete(state.slidesList, 'slide1') but I want to completely empty the state object (not delete the object itself) without losing reactivity on the object itself, when individual properties are deleted (using Vue.delete) removes reactive getters and setters, I believe, pls correct if this is wrong.
Does directly setting state.slideList = {} empties the object, while still being reactive? if yes then it implies state.slideList = {fname: 'Appu' } is a way to overwrite the object without emptying the object (if the goal is to overwrite the object completely with another object, rather than empty and re-write in it).
If not, what is the correct way to overwrite the state object with another new non-empty object.
Thanks
set adds a property to a reactive object, ensuring the new property is also reactive, so triggers view updates. This must be used to add
new properties to reactive objects, as Vue cannot detect normal
property additions. doc
module.js
import Vue from 'vue'
const initialState = {
foo: {},
bar: {},
// ...
}
const state = {...initialState}
const mutations = { // To reset a state
RESET_FOO (state) {
Vue.set(state, 'foo', initialState.foo)
},
UPDATE_FOO (state, payload) { // To update the state
Vue.set(state, 'foo', payload)
},
UPDATE_IN_FOO (state, { key, value }) { // To update a key in a state
Vue.set(state.foo, key, value)
},
RESET_MODULE (state) { // To reset the entire module
Object.assign(state, initialState)
}
}
Vuex has replaceState method that replaces store's root state.
Create a mutation that resets the state. Then, reset the state with a default value like this:
Object.assign(state, newState)

How can I clone data from Vuex state to local data?

How can I clone data from vuex state to local data attribute?
State
this.tsStore.shemes
Data Attribute
data () {
return { shemes: [] }
}
I've tried do this in updated () this.shemes = this.tsStore.shemes but it's seems like it has a binding left.. because when i delete one item in this.shemes on click i've also delete that item in the state and get the error of "Do not mutate vuex store state outside mutation handlers".
I need to clone the state and do what ever I need to do with that data and on the same time don't affect my state state.
Try
this.shemes = JSON.parse ( JSON.stringify ( this.tsStore.shemes) )
This will clone all value and objects from the array in the store.
You need to create a new array. this.tsStore.shemes give you a reference to the bound array.
You can try to use the spread operator or arr.slice() to create a new array with the same content.
notice that this is a shallow copy.
this.shemes = [...this.tsStore.shemes]
or
this.shemes = this.tsStore.shemes.slice()
Using cloneDeep is still the best way to go, here is an example
<script>
import { cloneDeep } from 'lodash-es'
...
const properlyClonedObject = cloneDeep(myDeeplyNestedObject)
...
</script>
It's bullet proof, battle-tested and is also a tree-shakable function.
If you need this for Nuxt, here is how to achieve this.
data(){
return {
shemes: null,
}
},
beforeMount() {
this.shemes = this.stateShemes
},
computed: {
stateShemes() { return this.tsState.shemes }
// OR that's how I do
stateShemes() { return this.$store.getters['shemes'] }
}
UPDATE
So you get some value from your state by using computed variables. You cannot just assign the value from you store in the data() block. So you should do it beforeMount. That way if you have a watcher for shemes variable, it won't trigger on assigning computed value. If you put it in mounted() hook, the watcher will trigger.
Also, can you explain why do you use this call this.tsState.shemes instead of this.$store.getters.shemes?

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

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