Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When is the plugin ready to be used? #15

Closed
PierBover opened this issue Nov 30, 2017 · 13 comments
Closed

When is the plugin ready to be used? #15

PierBover opened this issue Nov 30, 2017 · 13 comments

Comments

@PierBover
Copy link

PierBover commented Nov 30, 2017

Loading from localStorage seems immediate when the application starts, but when writing to the vuex store persistence doesn't seem to work until some time has passed.

If I do this in root component the state in localStorage doesn't change:

const root = new Vue({
	el: '#app',
	router,
	store,
	render: (h) => h(App),
	mounted () {
		store.commit('persistent/SET_TEST_VAR', true);
		console.log(store.state.persistent.test_var);
	}
});

If I do this instead it works fine:

setTimeout(() => {
	store.commit('persistent/SET_TEST_VAR', true);
	console.log(store.state.persistent.test_var);
}, 1000);
@kylewelsby
Copy link

kylewelsby commented Nov 30, 2017

I managed to find a workaround if you're using VueRouter

Given you have the strict RESTORE_MUTATION setup;

// ./store/index.js
import VuexPersistPatch from './plugins/vuex-persist-patch'

export default new Vuex.Store({
  mutations: Object.assign(mutations, {
    RESTORE_MUTATION: vuexLocal.RESTORE_MUTATION
  }),
  plugins: [
    vuesLocal.plugin,
    VuexPersistPatch()
  ]
})
// ./plugins/vuex-persist-patch.js
export default function vuexPersistPatch () {
  return store => {
    store._vm.$root.$data['vue-persist-patch-delay'] = true

    store.subscribe(mutation => {
      if (mutation.type === 'RESTORE_MUTATION') {
        store._vm.$root.$data['vue-persist-patch-delay'] = false

        store._vm.$root.$emit('storageReady')
      }
    })
  }
}

Take special note to using store._vm to receive the event from the bus.

// ./router/index.js
import store from '../store'

router.beforeEach((to, from, next) => {
  if (store._vm.$root.$data['vue-persist-patch-delay']) {

    // Hold the request, until the Storage is complete.
    store._vm.$root.$on('storageReady', () => {
      next({path: to.path, query: to.query, params: to.params})
    })
  } else {
    // YOUR OTHER RULES GO HERE
  }
})

@PierBover
Copy link
Author

Thanks @kylewelsby for the suggestion.

Seems overly complicated though since localStorage interactions are not async.

@PierBover
Copy link
Author

PierBover commented Nov 30, 2017

I ended up using vuex-persistedstate which works as expected.

@kylewelsby
Copy link

kylewelsby commented Dec 1, 2017 via email

@championswimmer
Copy link
Owner

The problem has been resolved in v1.0

If the store is not async (you're using localStorage), then vuex-persist will synchrnously restore state and you won't feel like "The store is not immediately restored"

@skyeewers
Copy link

@championswimmer I've just tested out the changes in version 1.0 and it seems as though your fix for this behavior does not apply when using sessionStorage() instead of localStorage().
Would it be possible to make the two types of storage behave the same, sync way, or is there something that would prevent someone from doing that? It'd really helpe if sessionStorage() could also work this way.
Thanks for your work on this project :)

@CosX
Copy link

CosX commented Dec 13, 2017

Thank you @PierBover. I managed to do this with localforage inspired by your plugin.

//first define a plugin that emits when the state has been persisted
const vuexPersistEmitter = () => {
    return store => {
        store.subscribe(mutation => {
            if (mutation.type === 'RESTORE_MUTATION') {
                store._vm.$root.$emit('storageReady');
            }
        });
    }
};

//I only needed to define strict mode here and not in the store.
const vuexLocal = new VuexPersistence({
    strictMode: true,
    asyncStorage: true,
    storage: localforage
});

export default new Vuex.Store({
   ...,
    mutations: {
        RESTORE_MUTATION: vuexLocal.RESTORE_MUTATION
    },
    plugins: [
        vuexLocal.plugin,
        vuexPersistEmitter()
      ]
});

And then in any kind of component:

const app = new Vue({
    store,
    ...App,
    mounted() {
        const self = this;
        self.$store._vm.$root.$on('storageReady', () => {
            self.$store.dispatch('somethingThatDependsOnTheStateBeingFilled');
        });
    }
});

@benitogf
Copy link

Hi, thanks for this plugin 👍 using custom methods for the storage (setItem, getItem, etc) instead of localforage will fail unless the flag here is set too

@karneaud
Copy link

Tried this plugin with 1.0.0 and "The store is not immediately restored". Is there a fix of this in any of the new versions or do I implement a workaround?

@karneaud
Copy link

Tries this plugin with 1.1.5 and still the same issue. using @CosX workaround does help but only if the state is restored....so I have to check the regular way and via store events

created(){
      this.setFetching({fetching: true})
      this.$store._vm.$root.$on('storageReady', () => {
        this.setGameStates()
        this.setFetching({fetching: false})
      });
    },
    mounted() {
      this.setGameStates()
    }

@rulrok
Copy link

rulrok commented Sep 24, 2018

Just a note if you are having this timing issue on production mode and is trying to use the subscribe trick.
As you will have strict set to false, the subscribe with RESTORE_MUTATION won't work.
That's because the store won't commit, but rather replace the state.

Look the code here:

vuex-persist/src/index.ts

Lines 163 to 167 in a5033b5

if (this.strictMode) {
store.commit('RESTORE_MUTATION', savedState)
} else {
store.replaceState(merge(store.state, savedState))
}

@championswimmer Can we have some event emitted here to know when that has happened on production mode?

EDIT:
Based on #3 (comment),
I have made this to be notified when storage has been replaced:

import store from '@/store' //<-- your store module

export default new VuexPersistence({
  storage: localForage,
  strictMode: false,
  asyncStorage: true,
  restoreState: (key, storage) => {
    return new Promise(resolve => {
      storage
        .getItem(key)
        .then(data => {
          resolve(data);
          store._vm.$f7.emit('storageReady');
        })
    })
  },
  ...
});

@bvelastegui
Copy link

I managed to find a workaround if you're using VueRouter

Given you have the strict RESTORE_MUTATION setup;

// ./store/index.js
import VuexPersistPatch from './plugins/vuex-persist-patch'

export default new Vuex.Store({
  mutations: Object.assign(mutations, {
    RESTORE_MUTATION: vuexLocal.RESTORE_MUTATION
  }),
  plugins: [
    vuesLocal.plugin,
    VuexPersistPatch()
  ]
})
// ./plugins/vuex-persist-patch.js
export default function vuexPersistPatch () {
  return store => {
    store._vm.$root.$data['vue-persist-patch-delay'] = true

    store.subscribe(mutation => {
      if (mutation.type === 'RESTORE_MUTATION') {
        store._vm.$root.$data['vue-persist-patch-delay'] = false

        store._vm.$root.$emit('storageReady')
      }
    })
  }
}

Take special note to using store._vm to receive the event from the bus.

// ./router/index.js
import store from '../store'

router.beforeEach((to, from, next) => {
  if (store._vm.$root.$data['vue-persist-patch-delay']) {

    // Hold the request, until the Storage is complete.
    store._vm.$root.$on('storageReady', () => {
      next({path: to.path, query: to.query, params: to.params})
    })
  } else {
    // YOUR OTHER RULES GO HERE
  }
})

@kylewelsby Thank you !! this served me!

@morphatic
Copy link

PR #107 is intended to address the issue raised by @rulrok. I've tested locally and found that I'm able to consistently get vuex-persist to restore the state before any other mutations are committed.

Illyism added a commit to Illyism/musicplayer that referenced this issue Jul 10, 2019
championswimmer added a commit that referenced this issue Aug 30, 2019
Emit `vuexPersistStateRestored` event when async store replaced (addresses #15)

Co-authored-by: Morgan Benton <morgan.benton@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants