How to clear state in vuex store?
Asked Answered
L

15

105

My state in vuex store is huge.

Is there a way to reset all the data in state in one go, instead of manually setting everything to null?

L answered 17/2, 2017 at 10:21 Comment(5)
With reset, you mean setting it to the intial state?Peavey
In my case clearing data is same as reseting since my store is empty intiialy.L
Just my 2 pence, but I actually break down state and load a store peculiar to whichever "core" component I'm using. You can import a specific store at runtime using webpack's async import method and assign it to your Vue instance. No need for the native "module" stuff and a whole lot slimmer for your client.Secunda
why not use @ianwalter/vuex-reset?Muffin
I don't understand why this is not included as a feature by default! In the end, the store itself has all the necessary infos to write its own resetState method...Nysa
C
175

I have just found the great solution that works for me.

const getDefaultState = () => {
  return {
    items: [],
    status: 'empty'
  }
}

// initial state
const state = getDefaultState()

const actions = {
  resetCartState ({ commit }) {
    commit('resetState')
  },
  addItem ({ state, commit }, item) { /* ... */ }
}

const mutations = {
  resetState (state) {
    // Merge rather than replace so we don't lose observers
    // https://github.com/vuejs/vuex/issues/1118
    Object.assign(state, getDefaultState())
  }
}

export default {
  state,
  getters: {},
  actions,
  mutations
}

Thanks to Taha Shashtari for the great solution.

Michael,

Chloride answered 2/8, 2018 at 12:0 Comment(12)
Excellent approach. Why does one need to use Object.assign(state, getDefaultState()) instead of state = getDefaultState()? Also, why have a function getDefaultState rather than just a variable defaultState?Nardoo
@michael-horojanski Is there a reason why you are merging Object.assign(state,getDefaultState()) instead of just setting the state to default? state = getDefaultState()?Bawl
@hitautodestruct, there is an issue that explains why do you need to reset state in the following way github.com/vuejs/vuex/issues/1118.Chloride
@MichaelHorojanski Thanks, I updated your answer with a small comment explaining the descisionBawl
Note that state can be a function so just juse state: getDefaultState in the export instead of calling getDefaultState().Paranoiac
If your state has nested object you probably need to do a deep assign or you'll lose nested observersAylsworth
Like a pro is ironically now a Bad Link :(Medievalism
most preferable solution and also the bestThurifer
Why is getDefaultState a function and not simply implemented as an object?Hydrophobia
This is the best solution! I was about to put an answer sharing the link, but then saw this answer.Aksum
If you need a global reset (e.g. when you logout a user) you can create a reset mutation in each module then call them in a central action this way: commit('nameSpace/resetState', null, { root: true })Prying
This is exactly what I am trying and find the solution. ThanksKesselring
I
18

Update after using the below solution a bit more

So it turns out that if you use replaceState with an empty object ({}) you end up bricking reactivity since your state props go away. So in essence you have to actually reset every property in state and then use store.replaceState(resetStateObject). For store without modules you'd essentially do something like:

let state = this.$store.state;
let newState = {};

Object.keys(state).forEach(key => {
  newState[key] = null; // or = initialState[key]
});

this.$store.replaceState(newState);

Update (from comments): What if one needs to only reset/define a single module and keep the rest as they were?

If you don't want to reset all your modules, you can just reset the modules you need and leave the other reset in their current state.

For example, say you have mutliple modules and you only want to reset module a to it's initial state, using the method above^, which we'll call resetStateA. Then you would clone the original state (that includes all the modules before resetting).

var currentState = deepClone(this.state)

where deepClone is your deep cloning method of choice (lodash has a good one). This clone has the current state of A before the reset. So let's overwrite that

var newState = Object.assign(currentState, {
  a: resetStateA
});

and use that new state with replaceState, which includes the current state of all you modules, except the module a with its initial state:

this.$store.replaceState(newState);

Original solution

I found this handy method in Vuex.store. You can clear all state quickly and painlessly by using replaceState, like this:

store.replaceState({})

It works with a single store or with modules, and it preserves the reactivity of all your state properties. See the Vuex api doc page, and find in page for replaceState.

For Modules

IF you're replacing a store with modules you'll have to include empty state objects for each module. So, for example, if you have modules a and b, you'd do:

store.replaceState({
  a: {},
  b: {}
})
Inhuman answered 10/1, 2018 at 11:59 Comment(5)
For some reason the code from the section For Modules in my case requires page reloading in order to reset everything.Attendant
Vue recommends using replaceState only for time-travel purposes. What if one needs to only reset/define a single module and keep the rest as they were. How would one go about doing this? I tried using mutations but state there is throws undefined if it is not stared.Kumamoto
@Kumamoto I updated the answer to deal with your question. Hope it helps!Inhuman
@Inhuman thanks for the update. In this case yes, you are replacing the entire state with all its modules. I guess my question was how do you elegantly only replace a single module while keeping the others. Right now I do this through mutations.Kumamoto
Yea, @KasparTr, the downside to replaceState is that it takes all the module state. However, if you don't expect to repeat this operation many times per second, or if your state is not several megabytes large, then you can argue that the perf loss is worth the readability and size of the procedure.Inhuman
B
9

You can declare an initial state and reset it to that state property by property. You can't just do state = initialState or you lose reactivity.

Here's how we do it in the application I'm working on:

let initialState = {
    "token": null,
    "user": {}
}

const state = Vue.util.extend({}, initialState)

const mutations = {
    RESET_STATE(state, payload) {
       for (let f in state) {
        Vue.set(state, f, initialState[f])
       }
    }
}
Billat answered 25/7, 2017 at 2:29 Comment(0)
R
7

I am not sure what you use case is, but I had to do something similar. When a user logs out, I want to clear the entire state of the app - so I just did window.reload. Maybe not exactly what you asked for, but if this is why you want to clear the store, maybe an alternative.

Racklin answered 8/1, 2018 at 5:23 Comment(5)
this seems to be the simplest solution, since i am logging out there's no harm reloading the window to clear the store and routing to login page in my opinion. Unless vue makes it simpler to automatically set the initial state (which in my case is empty '' ) there should have been something like this.$store.clear();Uniseptate
Depends on the use case. This just blows everything up, we don't really care about maintaining reactivity or state (actually, we want to get rid of everything) if we are doing a "full reset" such as a user logging out.Racklin
I think now you would do rather window.location.reloadCirri
This won't work if you use vuex-persistedstateSpinach
I went for the same solution but clearing local storage first localStorage.clear();window.location.reload();Dichloride
G
4

If you do a state = {}, you will remove the reactivity of the properties and your getters mutations will suddenly stop working.

you can have a sub-property like:

state: {
  subProperty: {
    a: '',
    lot: '',
    of: '',
    properties: '',
    .
    .
    .
  }
}

Doing a state.subProperty = {} should help, without losing the reactivity.

You should not have a state too big, break them down to different modules and import to your vuex store like so:

import Vue from 'vue'
import Vuex from 'vuex'
import authorization from './modules/authorization'
import profile from './modules/profile'

Vue.use(Vuex)

export const store = new Vuex.Store({
  modules: {
    authorization,
    profile
  }
})

now in your individual files:

// modules/authorization.js
import * as NameSpace from '../NameSpace'
import { someService } from '../../Services/something'

const state = {
  [NameSpace.AUTH_STATE]: {
    auth: {},
    error: null
  }
}

const getters = {
  [NameSpace.AUTH_GETTER]: state => {
    return state[NameSpace.AUTH_STATE]
  }
}

const mutations = {
  [NameSpace.AUTH_MUTATION]: (state, payload) => {
    state[NameSpace.AUTH_STATE] = payload
  },
}

const actions = {
  [NameSpace.ASYNC_AUTH_ACTION]: ({ commit }, payload) => {
    someService.login(payload.username, payload.password)
      .then((user) => {
        commit(NameSpace.AUTH_MUTATION, {auth: user, error: null})
      })
      .catch((error) => {
        commit(NameSpace.AUTH_MUTATION, {auth: [], error: error})
      })
  }
}

export default {
  state,
  getters,
  mutations,
  actions
}

If you should want to clear the state you can just have a mutation implement:

state[NameSpace.AUTH_STATE] = {
  auth: {},
  error: null
}
Geognosy answered 17/2, 2017 at 10:37 Comment(0)
M
3

Here's a solution that works in my app. I created a file named defaultState.js.

//defaultState.js
//the return value is the same as that in the state
const defaultState = () => {
    return {
       items: [],
       poles: {},
       ...
    }
}

export default defaultState

And then Where you want to use it

//anywhere you want to use it
//for example in your mutations.js
//when you've gotten your store object do

import defaultState from '/path/to/defaultState.js'

let mutations = {
    ...,
    clearStore(state){
        Object.assign(state, defaultState())
    },
}

export default mutations

Then in your store.js

import Vue from 'vue';
import Vuex from 'vuex';

import actions from './actions';
import getters from './getters';
import mutations from './mutations'; //import mutations
import state from './state';

Vue.use(Vuex);


export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters,
});

and That's it

Mccann answered 5/9, 2019 at 22:10 Comment(4)
state can't be changed directly, but a solution like this can be placed inside a mutationChyle
Yah. I used mine in a mutationMccann
ok so i'll upvote your solution if the code is inside a mutation :)Chyle
Updated @FrancescoVenturiniMccann
B
2

If you want to reset your entire state you can use the built in replaceState method.

Given a state set in index.js:

    const state = { user: '', token: '', products: [] /* etc. */ }
    const initialStateCopy = JSON.parse(JSON.stringify(state))

    export const store = new Vuex.Store({ state, /* getters, mutations, etc. */ })

    export function resetState() {
      store.replaceState(initialStateCopy)
    }

Then in your vue component (or anywhere) import resetState:

    import { resetState } from '@/store/index.js'

    // vue component usage, for example: logout
    {
      // ... data(), computed etc. omitted for brevity
      methods: {
        logout() { resetState() }
      }
    }
Bawl answered 4/4, 2019 at 8:43 Comment(0)
A
1

Based on these 2 answers (#1 #2) I made a workable code.

My structure of Vuex's index.js:

import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

import { header } from './header'
import { media } from './media'

Vue.use(Vuex)

const store = new Vuex.Store({
  plugins: [createPersistedState()],

  modules: {
    header,
    media
  }
})

export default store

Inside each module we need to move all states into separated var initialState and in mutation define a function resetState, like below for media.js:

const initialState = () => ({
  stateOne: 0,

  stateTwo: {
    isImportedSelected: false,
    isImportedIndeterminate: false,

    isImportedMaximized: false,
    isImportedSortedAsc: false,

    items: [],

  stateN: ...
  }
})

export const media = {
  namespaced: true,

  state: initialState, // <<---- Our States

  getters: {
  },

  actions: {
  },

  mutations: {
    resetState (state) {
      const initial = initialState()
      Object.keys(initial).forEach(key => { state[key] = initial[key] })
    },
  }

}

In Vue component we can use it like:

<template>
</template>

<script>
  import { mapMutations } from 'vuex'

  export default {
    name: 'SomeName',

    data () {
      return {
        dataOne: '',
        dataTwo: 2
      }
    },

    computed: {
    },

    methods: {
      ...mapMutations('media', [ // <<---- define module
        'resetState' // <<---- define mutation
      ]),

      logout () {
        this.resetState() // <<---- use mutation
        // ... any code if you need to do something here
      }
    },

    mounted () {
    }
  } // End of 'default'

</script>

<style>
</style>
Attendant answered 31/3, 2018 at 23:33 Comment(0)
L
1

Call router.go() or this.$router.go()

That will refresh the page and your state will be reset to how it was when the user first loaded the app.

Leu answered 13/3, 2019 at 23:32 Comment(1)
localStorage.clear(); this.$router.go(); Saved me!Equiponderate
E
1

Myself has read above and implemented a solution. could help you as well!!

All objects stored in Vue act as an observable. So if reference of a value is changed/mutated it triggers the actual value to be changed too.

So, Inorder to reset the state the initial store modules has to be copied as a value.

On logging out of an user, the same value has to be assigned for each modules as a copy.

This can be achieved as following:

Step 1: Create a copy of your initial module.

// store.ts

// Initial store with modules as an object
export const initialStoreModules = {
    user,
    recruitment,
};

export default new Vuex.Store({
    /**
     * Assign the modules to the store 
     * using lodash deepClone to avoid changing the initial store module values
     */
    modules: _.cloneDeep(initialStoreModules),
    mutations: {
        // reset default state modules by looping around the initialStoreModules
        [types.RESET_STATE](state: any) {
        _.forOwn(initialStoreModules, (value: IModule, key: string) => {
            state[key] = _.cloneDeep(value.state);
        });
        },
    }
});

Step 2: Call the action to mutate the state to initial state.

// user_action.ts
const logout = ({ commit }: any) => {
    commit(types.LOGOUT_INIT);
    new UserProxy().logout().then((response: any) => {
      router.push({
        name: 'login',
      });
      // reset the state
      commit(types.RESET_STATE);
    }).catch((err: any) => {
      commit(types.LOGOUT_FAIL, err);
    });
};
Ebonee answered 26/5, 2019 at 17:38 Comment(0)
H
1

You could take it easy by tiny package: vuex-extensions

Check out the example on CodeSandbox.

Creating Vuex.Store

import Vuex from 'vuex'
import { createStore } from 'vuex-extensions'

export default createStore(Vuex.Store, {
  plugins: []
  modules: {}
})
Store resets to initial State
// Vue Component
this.$store.reset()
// Vuex action
modules: {
  sub: {
    actions: {
      logout() {
        this.reset()
      }
    }
  }
}
Honourable answered 16/1, 2020 at 2:53 Comment(0)
H
0

You can do this

index.js

...

const store = new Vuex.Store({
    modules: {
       ...
    }
})

store.initialState = clone(store.state)

store.resetState = () => {
    store.replaceState(store.initialState)
}

export default store

Other place

this.$store.resetState()
Habana answered 9/3, 2021 at 14:32 Comment(0)
G
0
function initialState () {
  return { /* .. initial state ... */ }
}

export default {
  state: initialState,

  mutations: {
    reset (state) {
      // acquire initial state
      const s = initialState()
      Object.keys(s).forEach(key => {
        state[key] = s[key]
      })
    }
  }
}

This is an official recommendation issue

Gunsmith answered 10/6, 2021 at 9:2 Comment(0)
P
0

if you clear your complete vuex store use:

sessionStorage.clear();
Peart answered 2/9, 2021 at 6:51 Comment(0)
M
0

My way to reset named modules.

I create a dynamic vuex module on beforeCreate() hook in the layout.vue. (ES6 only)

// default.vue
beforeCreate() {
    this.$store.registerModule('initialStates', {
        state: () => ({ ...structuredClone(this.$store.state) })
    })
}

in the index.js vuex file, i created a resetModule() action :

//index.js
export const actions = {
    resetModule({ state, commit }, namespacedModule) {
        // acquire initial state
        const s = state.initialStates[namespacedModule]
        Object.keys(s).forEach((key) => {
            commit(`${namespacedModule}/mutate`, { property: `${key}`, with: s[key] })
        })
    }
}
//YourModuleName.js
export const mutations = {
    mutate(state, payload) {
        state[payload.property] = payload.with
    }
}

then, i call the reset action from anywhere and the namespacedModule is reseted :

this.$store.dispatch('resetModule', 'YourModuleName')
Mothy answered 6/4, 2023 at 11:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.