-
-
Notifications
You must be signed in to change notification settings - Fork 116
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
Emit vuexPersistStateRestored
event when async store replaced (addresses #15)
#118
Emit vuexPersistStateRestored
event when async store replaced (addresses #15)
#118
Conversation
Codecov Report
@@ Coverage Diff @@
## master #118 +/- ##
=======================================
Coverage 83.47% 83.47%
=======================================
Files 5 5
Lines 115 115
Branches 38 38
=======================================
Hits 96 96
Misses 7 7
Partials 12 12
Continue to review full report at Codecov.
|
For anyone who may be waiting on this PR to be merged, in the meantime, you can install a patched version of this package directly from my fork as follows: npm install --save github:morphatic/vuex-persist Or, if you had already installed the package, but want the patched version, update the relevant line from your // package.json
{
dependencies: {
// ... other stuff
"vuex-persist": "github:morphatic/vuex-persist"
}
} Hth |
May I suggest a promise based implementation for cleaner code. // index.ts
/**
* Async version of plugin
* @param {Store<S>} store
*/
this.plugin = (store: Store<S>) => {
(store as any).restored = ((this.restoreState(this.key, this.storage)) as Promise<S>).then((savedState) => {
/**
* If in strict mode, do only via mutation
*/
if (this.strictMode) {
store.commit('RESTORE_MUTATION', savedState)
} else {
store.replaceState(merge(store.state, savedState || {}))
}
this.subscriber(store)((mutation: MutationPayload, state: S) => {
if (this.filter(mutation)) {
this._mutex.enqueue(
this.saveState(this.key, this.reducer(state), this.storage) as Promise<void>
)
}
})
this.subscribed = true
})
} The // in src/router.js
const waitForStorageToBeReady = async (to, from, next) => {
await store.restored
next()
} Thanks |
@hotdogee I agree your way is much cleaner! I tried making the change in my fork, wrote a test for it, and it appears to work perfectly. There might be one issue it doesn't address, but perhaps you have an equally elegant workaround, or it could be I'm not thinking through it clearly. The issue is that the What happens when you hit the router after the initial restore and you hit the If it works, I'll update the PR to use your approach. I like your way much better. Wish I'd thought of it!! |
@morphatic Awesome, I'm glad you could make it work.
The plugin Promise is created and assigned to the
Yes, it is possible to get stuck, but it is the same case if // in src/router.js
const waitForStorageToBeReady = async (to, from, next) => {
try {
await Promise.race([
store.restored,
new Promise((resolve, reject) => {
const ms = 3000
const id = setTimeout(() => {
clearTimeout(id)
reject(new Error(`Timed out in ${ms} ms.`))
}, ms)
})
])
} catch (error) {
// handle the case where the store was never successfully restored
}
next()
} Warning: sorry, I did not have a computer on hand to actually test the code above at this moment. Thanks~ |
@hotdogee Thank you for the fantastic suggestions! I went ahead and revised this PR to use your approach instead of the one that I had before. In my use case, there are some things I need to do only after the first restore. Here's what I found out: // I tried this first, but it did NOT do what I intended...
const waitForStorageToBeReady = async (to, from, next) => {
await store.restored.then(
() => {
// this code will run on EVERY route request
}
)
next()
} I did not want the post-restore code to run on every request, so I did something like this: let previouslyRestored = false
const waitForStorageToBeReady = async (to, from, next) => {
await store.restored
if (!previouslyRestored) {
// do the things you want to do only once after the store is restored
previouslyRestored = true
}
next()
}
|
Would prefer something like this #121 than this PR, if you want to do that instead, make a PR for that please 😇 |
So this PR actually makes v2.1.0 unusable. like @morphatic mentioned... there is a silent failure when the store is set to strict but the plugin is not. this results in the app crashing silently and leaving everything unusable. This is particularly troubling because tools like Nuxt or a project generated by the Vue CLI will put the store in to strict-mode when running in non-production. @championswimmer Can you please update the documentation to mention that if someone uses the |
Send a PR with an updated README please ? :)
…On Thu, 12 Sep, 2019, 5:04 AM Maurice Williams, ***@***.***> wrote:
So this PR actually makes v2.1.0 unusable. like @morphatic
<https://github.com/morphatic> mentioned... there is a silent failure
when the store is set to strict but the plugin is not. this results in the
app crashing silently and leaving everything unusable.
@championswimmer <https://github.com/championswimmer> Can you please
update the documentation to mention that if someone uses the
router.beforeEach trick.... then then plugin and the store MUST both be
in the same "strict" state.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#118?email_source=notifications&email_token=AAKD7SXILRNHMVFKRLDLYDTQJF6CDA5CNFSM4HO3FTOKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6QGJ5A#issuecomment-530605300>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAKD7SUUD6RRR6QUMNT55ADQJF6CDANCNFSM4HO3FTOA>
.
|
Addresses issue raised in issue 15 by @rulrok. Also addresses #56. Supersedes #107.
This PR contains updated
index.ts
as well asREADME.md
to update the documentation on how to use the new event. New functionality is tested intest/async-plugin-emits-restored.spec.ts
.As [noted in the docs](https://github.com/championswimmer/vuex-persist#note-on-localforage and-async-stores), the store is not immediately restored from async stores like
localForage
. This can have the unfortunate side effect of overwriting mutations to the store that happen beforevuex-persist
has a chance to do its thing. In strict mode, you can create a plugin to subscribe toRESTORE_MUTATION
so that you tell your app to wait until the state has been restored before committing any further mutations. (Issue #15 demonstrates how to write such a plugin.) However, since you should turn strict mode off in production, and sincevuex
doesn't currently provide any kind of notification whenreplaceState()
has been called, this PR would causevuex-persist
to emit avuexPersistStateRestored
event and also set avuexPersistStateRestored
flag to let you know the state has been restored and that it is now safe to commit any mutations that modify the stored state.Here's an example of a
beforeEach()
hook invuex-router
that will cause your app to wait forvuex-persist
to restore the state before taking any further actions:Note:
store._vm.$root.$data['vuexPersistStateRestored']
will beundefined
and therefore "falsy" prior to being set totrue
by thevuex-persist
plugin. There should be no need to explicitly give it a value at any point.