Skip to content

Clear all stores or set them all to its initial state #1118

@JonaMX

Description

@JonaMX

What problem does this feature solve?

I have several modules defined on my store, with its own store on each module:

export default new Vuex.Store({
  modules: {
    user,
    items,
    invoices,
    ... // A bunch of other modules
  }
})

The issue is that when the user logs out the app, all the information in the store remains since no mutation is being called to effect them or the set them to its initial state, therefore when another user logs in he can see information of the previous user, I know that I can just create a new mutation to set the store to its initial state, but that means that I'd need to call this mutation for each module that I have.

Is there a way to clear them all?

What does the proposed API look like?

It would be great to have a reserved mutation named 'clearAll' or alike, that resets all the module stores to its initial state as they were defined

...mapMutations([
  'clearAll'
])

Then on the logout method

logout: function () {
  this.$store.dispatch('logout').then(
    () => {
      this.$router.push('/login')
      this.clearAll()
    }
  )
},

Activity

robokozo

robokozo commented on Jan 8, 2018

@robokozo

You can easily implement something like this on your own.

On your 'root' Vuex store you can implement an action that calls each individual modules 'reset' mutation.

    actions: {
        clearAll({ commit }){
            commit("moduleA/reset")
            commit("moduleC/reset")
        }
    }

This gives you greater control over a generic solution because you might have modules that you wouldn't want to clear under some circumstances.

ktsn

ktsn commented on Jan 9, 2018

@ktsn
Member

As @robodude described.

FYI, you can declare a function returning an initial state to reset a state.

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]
      })
    }
  }
}
DarynHolmes

DarynHolmes commented on Mar 28, 2018

@DarynHolmes

Thanks for this. I was wondering why does reset loop over all the keys? Why can't is just set state to initialState() ?

kiaking

kiaking commented on Mar 28, 2018

@kiaking
Member

Because if you do that (state = initialState) then the state object will loose it's observer and it won't be reactive anymore. Same as plain object behavior in JavaScript.

const object = { key: 'value' }

function one (o) {
  o.key = 'one'
}

one(object)

console.log(object) // <- { key: 'value' }

function two (o) {
  o = { key: 'two' }
}

two(object)

console.log(object) // <- { key: 'value' } Not modified!
DarynHolmes

DarynHolmes commented on Mar 28, 2018

@DarynHolmes

Thanks @kiaking for the fast and helpful response.

peacefulseeker

peacefulseeker commented on May 24, 2018

@peacefulseeker

Not sure why, but even after creating initialState function, which returns clean object, vue observer was assigned to it after. Probably did something wrong.
But than came across kind of Object.freeze() decision:

// state.js

const initialState = {
  pflegegrad: 0,
  progress: 0,
  result: {
    initial: 0,
    final: 0,
  },
  completedModule: 0,
  currentModule: 1,
  modules: ...nestedObj,
}

export default () => ({
  ...JSON.parse(JSON.stringify(initialState)),
})

And it worked liek a charm. May be the problem was also in deeply nested Objects.

JFGHT

JFGHT commented on Jun 1, 2018

@JFGHT
torbentschechne

torbentschechne commented on Jun 12, 2018

@torbentschechne

@ktsn Thanks for your proposal, but this does not work nested object states. Do you have a solution as well?

maksnester

maksnester commented on Jun 27, 2018

@maksnester
Object.keys(s).forEach(key => {
        state[key] = s[key]
      })

In case if there is no additional keys added in state, would Object.assign(state, initialState()) bring the same result? In terms of handling getters correctly and so on.

NJM8

NJM8 commented on Aug 9, 2018

@NJM8

I wanted to chime in with my variation on the great solution provided by @ktsn. I have 10ish vuex modules and like to keep things super DRY. So I defined the same initialState function, but the only other thing I do in the module is put this on the modules state.

In user.js module

function initialState() {
  return {
    status: "",
    profile: {}
  };
}

export const state = {
  initialState: initialState,
  status: initialState().status,
  profile: initialState().profile
};

export const mutations = {
  SET_STATUS: (state, payload) => {
    state.status = payload;
  },
  SET_PROFILE: (state, payload) => {
    state.profile = payload;
  }
};

Then define a global action that will check the presence of initialState on each modules state, and if it has it, loop over the keys and commit the mutation to reset it. I used snake case for all my initial state props and mutations to keep it simple.

In global actions

actions: {
    resetAllState({ dispatch }) {
      for (const currentModule in modules) {
        if (modules[currentModule].state.hasOwnProperty("initialState")) {
          dispatch("resetModuleState", currentModule);
        }
      }
    },
    resetModuleState: ({ commit }, currentModule) => {
      const initialState = modules[currentModule].state.initialState;
      Object.keys(initialState).forEach(key => {
        commit(`${currentModule}/SET_${key.toUpperCase()}`, initialState[key]);
      });
    }
  },

Any feedback or improvements appreciated!

starfruitsolutions

starfruitsolutions commented on Sep 3, 2018

@starfruitsolutions

When you do this:

 Object.keys(s).forEach(key => {
        state[key] = initialState[key]
      })

You're using the initial state object for the state, so next time you need to clear it, it won't be in the "initial state". That's why the solution provided by @ktsn requires a function to return a new initial state. You don't need to do this if you:

  1. import the initial state(or clone it) before use
  2. use Object.assign when you actually reset the state.

Here's an example that will clear the entire state including modules:

// import modules
import cart from './modules/cart'
import invoices from './modules/invoices'
import person from './modules/person'

// initial state
let initialState = {
  cart: cart.state,
  invoices: invoices.state,
  person: person.state
}

export default new Vuex.Store({
  modules: {
    cart,
    invoices,
    person
  },
  mutations: {
    reset (state) {
      Object.keys(state).forEach(key => {
        Object.assign(state[key], initialState[key])
      })
    }
  }
})
sjmcdowall

sjmcdowall commented on Sep 24, 2018

@sjmcdowall

@NJM8 -- Love the way you are doing this, although in Typescript I am having some headaches ..LOL

However, one quick question .. Why are your resetXXXX actions and not pure mutations? Well maybe the overall resetAllState should be (although not sure about that) ?? They aren't doing anything really than doing mutations .. no sides effects that I can see..

NJM8

NJM8 commented on Sep 25, 2018

@NJM8

@sjmcdowall Thanks, glad you like it, good luck with the typescript, I have no experience with that.

My resetXXXX are all actions purely out of preference. I try to use actions for everything to have a single pipeline for how data is affected. Some of my early VueJs apps turned out to be a mess because I wasn't strict with that and they were very hard to debug. Now getters get, mutations set, and actions do all the work. Helps me keep things clean and organized. Although yes it can be more code sometimes.

sjmcdowall

sjmcdowall commented on Sep 25, 2018

@sjmcdowall

@NJM8 -- The only thing I don't like about actions -- unless you need them -- is that store.dispatch() always returns a Promise .. which then you have to handle .. (or should.. Typescript sort of forces you to do it) .. whereas pure mutations cannot be Async .. so no async stuff when using them .. but I do make sure a mutation truly only mutates the state .. no other side effects !

31 remaining items

ikramkhizar

ikramkhizar commented on Sep 19, 2020

@ikramkhizar

Try that.
setTimeout(()=>
{
window.location.href = "/";
},3000);

RonaldCast

RonaldCast commented on Oct 8, 2020

@RonaldCast

The method that worked for me was this:

import Vue from "vue";
import Vuex from "vuex";

import login from "./modules/login";
import profile from "./modules/profile";

let initialState ={
  login:login.state,
  profile:profile.state,
}

//Convert object in string 
const COPY = JSON.stringify(initialState)

export default new Vuex.Store({
  modules: {
    login,
    profile,
  },
  mutations: {
    RESET_STATE(state) {

      //Convert string in object 
      let copyState = JSON.parse(COPY);
      Object.keys(state).forEach(key => {
 
        Object.assign(state[key], copyState[key])
      })
    }
}
});
jvhellemondt

jvhellemondt commented on Dec 18, 2020

@jvhellemondt

It feels kinda hacky to do it as follows. But it works..

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

Any objections I'm missing? I believe reactivity is still in order. But again, it feels hacky..

evgencode

evgencode commented on Feb 4, 2021

@evgencode
let initialState = {
 cart: cart.state,
 invoices: invoices.state,
 person: person.state
}

export default new Vuex.Store({
 modules: {
   cart,
   invoices,
   person
 },
 mutations: {
   reset (state) {
     Object.keys(state).forEach(key => {
       Object.assign(state[key], initialState[key])
     })
   }
 }
})
Object.assign(state[key], initialState[key])

If the state for this key has already been changed, the changed state will be here. As a result, we will receive the same state as before reset. There will be a reference to the changed object

therealcoder1337

therealcoder1337 commented on Feb 23, 2021

@therealcoder1337

would be nice to have a reset feature directly integrated to vuex, especially since you can already define module state as a function to improve reusability: https://vuex.vuejs.org/guide/modules.html#module-reuse

jskitz

jskitz commented on Jul 6, 2021

@jskitz

Instead of walking the state and setting each back to it's initial state, why not just reload the app if you want all state moved back to its initial state? On logout in my app, I do the following things:

this.$router.replace({ name: 'signin' }) // This redirects the user to signin
window.location.reload()  // This just reloads the app at the signin prompt

There is a small little flash that I'm assuming the user is really not going to notice because after all, they are logging out of the app. But this has the intended behavior of just resetting all vuex storage back to its initial state. It's less control based on the other solutions here, but on logout, I don't see any reason why we would need to retain any state. Is there something I am missing with this solution?

NJM8

NJM8 commented on Jul 6, 2021

@NJM8

@jskitz I think that is a great simple solution for an app that loads quickly with a boss that doesn't mind the small little flash 😉 . One utility for this functionality was having large amounts of data loaded related to an entity, then you want to unload and view a different entity. Of course you should be saving both but sometimes it doesn't make sense or makes the app too complex. Also playing with VuexPersist can make a state reset function very helpful.

jskitz

jskitz commented on Jul 6, 2021

@jskitz

@NJM8 that makes a lot of sense. Thanks for elaborating on cases where this would not be a great solution. Much appreciated!

metalsadman

metalsadman commented on Sep 29, 2021

@metalsadman

@jskitz I think that is a great simple solution for an app that loads quickly with a boss that doesn't mind the small little flash 😉 . One utility for this functionality was having large amounts of data loaded related to an entity, then you want to unload and view a different entity. Of course you should be saving both but sometimes it doesn't make sense or makes the app too complex. Also playing with VuexPersist can make a state reset function very helpful.

which is very slow walking trough many modules and when data is already populated in Vue3+Vuex4. I've resorted back to reloading in the end since i have functionality like you've described :(.

huybuidac

huybuidac commented on Oct 4, 2021

@huybuidac

@metalsadman Did you try vuex-extensions?

Just call store.reset to reset all stores.

BonBonSlick

BonBonSlick commented on Oct 21, 2021

@BonBonSlick

Same questions as @huybuidac asked, anyone tried https://github.com/huybuidac/vuex-extensions ? Any edge cases and side effects? Difficulties? Performance? Issues?

Same to https://github.com/ianwalter/vuex-reset

BonBonSlick

BonBonSlick commented on Oct 21, 2021

@BonBonSlick

@j623415 its impossible to call router.go() without params in TS. You have to pass number.
@huybuidac In vue 2 + TS above packages vuex-reset and vuex-extensions do not work

jatin-maropost

jatin-maropost commented on Dec 7, 2022

@jatin-maropost

Because if you do that (state = initialState) then the state object will loose it's observer and it won't be reactive anymore. Same as plain object behavior in JavaScript.

const object = { key: 'value' }

function one (o) {
  o.key = 'one'
}

one(object)

console.log(object) // <- { key: 'value' }

function two (o) {
  o = { key: 'two' }
}

two(object)

console.log(object) // <- { key: 'value' } Not modified!

Thanks for sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @brendon@DarynHolmes@jskitz@JonaMX@robsonsobral

      Issue actions

        Clear all stores or set them all to its initial state · Issue #1118 · vuejs/vuex