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)
Related
I am learning Vuex and my understanding so far has been that mutations should be simple functions that update the state directly using something like state.property = value or state.object = {payload}, e.g.:
SET_USER_DATA (state, userData) {
state.user = userData
}
I am working through a course from Vue Mastery that contains mutations that look like the code below which does not reference the state object within the body of the mutation at all:
CREATE_TASK(state, { tasks, name }) {
tasks.push({ name, id: generateId(), description: "" });
},
UPDATE_TASK(state, { task, field, value }) {
Vue.set(task, field, value);
},
CREATE_TASK creates a new empty task and adds it to the tasks array using tasks.push(), but shouldn't a reference to the state object be required to update the state? E.g. state.tasks.push()? How does simply pushing an item onto a bare array commit the change to the state?
In the second example, they use Vue.set() to update the value of a specific field within a task (e.g. name, description), but again, there is no reference to the state object here.
The best I can figure is that they relying on Vue's native reactivity to automatically update the state when calling Vue.set() or Array.push(). But if that is the case, wouldn't any usage of Vue.set() or Array.push() inside of a component also immediately update the state (violating the rule that state changes should only be handled within a mutation?
I have a button that’s set to update the a store object using Vue.set but the getter for that same piece of data in a different component isn’t reactive until I change the state using a different component method.
The state object in question is set up as a hash that's keyed by UUID's. The object is generated and then added to the state object with Vue.set
The button is set to dispatch an action, which I see it going through immedietely in the devtool, that does this:
mutations: {
COMPLETE_STEP(state, uuid) {
let chat = state.chatStates[uuid];
let step = chat.currentStep;
Vue.set(chat.data[step], "complete", true);
}
},
actions: {
completeStep({ commit }, uuid) {
commit("COMPLETE_STEP", uuid);
}
},
Now, when I want to grab that data, I have a getter that grabs that data. This doesn't run until I do something else that causes a re-render:
getters: {
getChatStepComplete: state => (uuid, step) => {
let chatState = state.chatStates[uuid];
return chatState.data[step].complete;
},
}
I want the getter to show the updated change right away instead of waiting to update on a different re-render. How do I make that happen?
Figured out my issue: I wasn’t creating the data array when I first create and add chat to the state. Once I started initializing it to an empty array, it’s started being reactive.
I just want to change data in state of VueX without pass value through following step Action > Mutation > State then getData from state of VueX in other component, Is it possible to do or anyone has another best way to do send value with array to ...mapAction please explain me,
Actually, I just want to send data with array to other component which the data will be change every time when user selected checkbox on Treevue component that I used it.
Thank a lot.
## FilterList.vue ##
export default {
data() {
return {
listSelected: ['aa','bb','cc','...'], // this value will mutate when user has selected checkbox
}
}
}
=================================================================
## store.js ##
export default new Vuex.Store({
state = {
dataSelected: [ ]
},
mutation = {
FILTERSELECTED(state, payload) {
state.selected = payload
}
},
action = {
hasSelected(context,param) {
context.commit('FILTERSELECTED',param)
}
},
getters = {
getSelected: state => state.dataSelected,
}
strict: true
})
You can set strict: false and change data directly, but I wouldn't recommend it.
You'll lose the benefit Vuex provides, i'd rather share that object outside vuex.
Not every change needs to be synced with the store, it depends on the scenario.
For a EditUser component as example, I'll start with a deep copy of the user object from the store:
this.tmpUser = JSON.parse(JSON.stringify(this.$store.state.user))
This tmpUser is disconnected from the store and won't generate warnings (or updates) when you change its properties.
When the user presses the "save" button, i'll send the changed object back to the store:
this.$store.dispatch("user/save", this.tmpUser)
Which updated the instance in the store and allows the other parts of the application to see the changes.
I also only write actions when async (fetching/saving data) is needed.
For the sync operations I only write the mutations and the use the mapMutations helper or call $store.commit("mutation") directly.
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?
This is more a "which method should I use" question, rather than a how to.
I have the following in my Vuex.Store() instance:
store.js:
export default new Vuex.Store({
state: {
acceptedTermsAndConditions: false
},
})
From various components I'm emitting an event which sets this.$store.state.acceptedTermsAndConditions to true or false, dependent on different User inputs.
However, in my component I would set the checked value of a "Accepts T&Cs" checkbox to this value, something like this:
components/Component.Vue:
data () {
return {
form: {
checkboxTermsAndConditions: this.$store.state.acceptedTermsAndConditions
}
}
}
I'm just not sure what method handles this? Does a solution require a getter? If not, what is the best way to watch for state changes and set data values accordingly?
If you want to set the checkbox state based on the stored value, you should use the computed object and the mapGetters helper function in your component:
https://vuex.vuejs.org/guide/getters.html#the-mapgetters-helper
computed: {
...mapGetters(['acceptedTermsAndConditions'])
}
Like this, the value will be accessible in your component. If you want to do the contrary (refresh the store based on the checkbox value), you should create a mutation in your store and you should use this in your component:
methods: {
...mapMutations(['setTACcheckbox'])
}
This way, inside your component you can refresh the store value with this.setTACcheckbox(value).