How can I clone data from Vuex state to local data? - vue.js

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?

Related

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)

Vuex state object length not reactive on computed property

I'm trying to get the length of state object from a computed property but it seems to be not reactive.
the state structure:
state: {
user: {
cards: {},
}
}
the getter in my store:
cardCount(state) {
return Object.keys(state.user.cards).length
}
and a computed prop:
calcLeft() {
return this.$store.getters.cardsLeft - this.$store.getters.cardCount
}
on state.user.cards change, i expect from cardCount to return a different value to the computed prop, but that's not happening, it's just stay the same.
Thanks to skirtle, iv'e followed the the usual caveats (vuex),
to change a state prop can be done by the following syntax but it won't be reactive:
state.obj[key] = somevalue
to do that we can use both Vue way or spread syntax to achieve reactivity:
the Vue way:
Vue.set(state.obj, key, value)
or the spread syntax like that:
state.obj = {...state.obj, key: value}

Computed function running without to call it

I'm setting an array in my data property through a computed function and it's working. But I wonder how is possible if I don't call it anywhere?
If I try to add a console.log in my function it doesn't print anything, but it's still setting my data, how is that possible?
My data:
data() {
return {
projects: []
};
},
My computed:
computed: {
loadedProjects() {
console.log("Hello there")
this.projects = this.$store.getters.loadedProjects
}
},
I expect that it doesn't run because I'm not calling, and if it is running(I don't know why) to print the console.log before to set my data. Any clarification?
Thanks:)
You're confusing computed props with methods. If you want to have a method like above that sets a data value of your vue instace, you should use a method, not a computed prop:
data() {
return {
projects: []
};
},
methods: {
loadProjects() {
console.log("Hello there")
this.projects = this.$store.getters.loadedProjects
}
}
This would get the value of this.$store.getters.loadedProjects once and assign it to your local projects value. Now since you're using Vuex, you probably want your local reference to stay in sync with updates you do to the store value. This is where computed props come in handy. You actually won't need the projects in data at all. All you need is the computed prop:
computed: {
projects() {
return this.$store.getters.loadedProjects
}
},
Now vue will update your local reference to projects whenever the store updates. Then you can use it just like a normal value in your template. For example
<template>
<div v-for='item in projects' :key='item.uuid'>
{{item.name}}
</div>
</template>
Avoid side effects in your computed properties, e.g. assigning values directly, computed values should always return a value themselves. This could be applying a filter to your existing data e.g.
computed: {
completedProjects() {
return this.$store.getters.loadedProjects.filter(x => x.projectCompleted)
},
projectIds() {
return this.$store.getters.loadedProjects.map(x => x.uuid)
}
}
You get the idea..
More about best practices to bring vuex state to your components here: https://vuex.vuejs.org/guide/state.html
Computed props docs:
https://v2.vuejs.org/v2/guide/computed.html
You should check Vue docs about computed properties and methods
and shouldn't run methods inside computed property getter
https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed.

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.