NuxtJSのSSRモードで、vuex-persistedstateによるデータ永続化を適用してしまいSSRのfetchライフサイクルでstoreに設定したデータが上書きされてしまった。これは、私がvuex-persistedstateの使用方法を誤っただけである。SSRモードで動かす場合は、クライアントサイドで永続化したいpathにのみ適用すべし(自分への戒め)。
stateが上書きされてしまったケース
具体的には以下のような使い方をしてしまっていた。
- vuex-persistedstateをpluginとしてロード
- クライアントサイドでstoreにデータ書き込み(この段階でlocalStorageにデータが書かれている)
- SSRでサーバサイドでfetch処理でstateにデータを書き込む
期待する動きは、3で初回ページアクセスしてサーバサイドでcommitしたstateがクライアントサイドで復元される、である。
しかし、3番目のステップでSSRで設定したstateデータがクライアントサイドで復元されると期待するものの、vuex-persistedstateプラグインの永続化処理により、以前にlocalStorageに書き込んだ値で上書きされてしまう、という訳である
// nuxt.config.js
plugins: [
{ src: '~/plugins/persistedState.js', mode: 'client' },
]
// pages/index.vue
fetch({ store }) {
store.commit('setCounter', 100) // counter=100
},
methods: {
doSomething() {
this.$store.commit('setCounter', 9999) // localStorage => counter=9999
}
}
// store/index.js
export const state = () => ({
counter: 0,
})
export const mutations = {
setCounter(state, value) {
state.counter = value
},
}
import createPersistedState from 'vuex-persistedstate'
export default ({ store }) => {
createPersistedState({ key: 'share' })(store) // => counter=9999 not but 100
}
プラグインロードのタイミング
NuxtJSでは以下のようにpluginとして組み込める。クライアント再度でpluginがロードされるタイミングは、ライフサイクルでは以下となる。
- Receives the HTML
- Loading assets (e.g. JavaScript)
- client-side Nuxt plugin ★ここ
- in order as defined in nuxt.config.js
- Vue Hydration
- Middleware
- Global middleware
- Layout middleware
- Route middleware
- asyncData (blocking)
- beforeCreate (Vue lifecycle method)
- created (Vue lifecycle method)
- The new fetch (top to bottom, siblings = parallel) (non-blocking)
- beforeMount (Vue lifecycle method)
- mounted (Vue lifecycle method)
引用:https://nuxtjs.org/docs/concepts/nuxt-lifecycle/
Stateのrestoreのタイミング
サーバーサイドでcommitされたstateの情報は、ページアクセスのレスポンスデータの中でシリアライズされて送信される。そして、アプリケーション初期化のタイミングでstateに復元される。
// .nuxt/index.js
if (process.client) {
// Replace store state before plugins execution
if (window.__NUXT__ && window.__NUXT__.state) {
store.replaceState(window.__NUXT__.state)
}
}
// Add enablePreview(previewData = {}) in context for plugins
if (process.static && process.client) {
app.context.enablePreview = function (previewData = {}) {
app.previewData = Object.assign({}, previewData)
inject('preview', previewData)
}
}
// Plugin execution
if (typeof nuxt_plugin_plugin_b9ce5b40 === 'function') {
await nuxt_plugin_plugin_b9ce5b40(app.context, inject)
}
...
store.replaceStateの復元段階では、まだプラグインの初期化はされていない。プラグインの初期化が呼ばれるのは、コメント // Plugin executionの以降になるので、上記で復元されたstateは上書きされてしまう。
参考リンク
- https://nuxtjs.org/docs/concepts/nuxt-lifecycle/
- https://github.com/robinvdvleuten/vuex-persistedstate


コメント