Do you want to request a feature or report a bug?
Yes i want to request a feature
What is the current behavior?
Nothing happens
If the current behavior is a bug, please provide the steps to reproduce.
What is the expected behavior?
Setting cookies
If this is a feature request, what is motivation or use case for changing the behavior?
I need use persisted state in ssr, but can't understand how to implement this, so maybe you can give me some tips?
For those who want to use in SSR before a fix is launched, I managed this way:
storage.js
import CreatePersistedState from 'vuex-persistedstate'
let PersistedState
if (process.browser) {
PersistedState = CreatePersistedState(yourOptions)
}
export default PersistedState
store.js
import CreatePersistedState from 'src/util/plugins/storage'
...
const plugins = []
if (process.browser) {
plugins.push(CreatePersistedState)
}
export default function createStore() {
return new Vuex.Store({
state,
modules,
actions,
mutations,
getters,
strict: false,
plugins: plugins
})
}
@waghcwb Hi, thank you for your proposed solution. The local storage on my SSR works, however my state is lost on page reload, could help us a little bit more on how you managed to make the Vuex state actually persist? Thanks in advance.
Same issue here - not able to get it to work with HN2 example.
I am currently using setTimeout inside the created method to guarantee that my store has been loaded before taking any action. However, it is not a good approach. I am looking for a way like a promise which the resolve will be thrown when the state is loaded from the localStorage.
I've tried this plugin again, but now I'm using Nuxt and I'm facing this issue too. The whole state is lost on a page refresh.
@waghcwb just add localStorage.js file in plugin directory:
import createPersistedState from 'vuex-persistedstate'
export default ({store}) => {
window.onNuxtReady(() => {
createPersistedState({})(store)
})
}
and then in nuxt.config.js add to plugins array:
plugins: [
{
src: '@/plugins/localStorage.js',
ssr: false
}
],
it's gonna work but it's not perfect because when you have some boolean in state and lets say that it is false then elements displayed conditionally on this boolean will show when loading the SPA and hide after it is loaded. It will cause that the page will be "jumping" which looks very ugly.
This plugin was never meant to be used with Nuxt.js, so I am gonna close this for now. Please move to a appropiate support channel like StackOverflow.
Hi, I know this is an old topic but while looking for solutions for persisting state and Nuxt serverside rendering (so to have everything ready on load, including stuff you might display in a template based on user's store), I ran into this topic. You can get it to work, but it's not as straightforward. Anyway, maybe it'll help someone else before they waste a couple of hours :)
So, since you don't have access to localStorage on server-side, you are going to have to use cookies for this. There is a trade-off, though, as you cannot store as much data in your cookies as you can in localStorage. However, if you really need to store a lot of data in your state there are other workarounds.
This example is perfect if you only need to store a bit of data in your state (eg. user settings like language, currency, location, etc).
First thing's first, createPersistedState and use cookies for storage.
// plugins/storage.js file
import createPersistedState from 'vuex-persistedstate'
import * as Cookies from 'js-cookie'
export default ({store}) => {
createPersistedState({
storage: {
getItem: key => Cookies.get(key),
setItem: (key, value) => Cookies.set(key, value, { expires: 3, secure: false }),
removeItem: key => Cookies.remove(key),
},
})(store);
}
Then register your plugin for nuxt. Please note - you can use ssr: true or ssr: false, didn't seem to make any difference for me.
// nuxt.config.js
module.exports = {
...
plugins: [{ src: '~/plugins/storage.js', ssr: true }],
...
}
Lastly, you have to populate the store on nuxtServerInit. In this example, the store is pretty simple. The state just has a version property.
// store/index.js or store/index.ts if you use TS
export function state() {
return {
version: null,
};
}
export const mutations = {
setVersion(state, version: string) {
state.version = version;
}
};
export const actions = {
async nuxtServerInit({ commit }, { req }) {
if (req.cookies.vuex) {
const STATE = JSON.parse(req.cookies.vuex);
commit('setVersion', STATE.version);
}
},
};
Given a component below (note, I am using TS but it's the same for JS)
// pages/index.vue
<template>
<div class="page-index">
<h1>Example has version {{ version }}</h1>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator';
@Component
export default class PageIndex extends Vue {
version: string = this.$store.state.version;
}
</script>
The output of view-source:http://localhost:3000/ (if you're running it locally and have FOOBAR in your store.state.version, only extracting the HTML of the component for clarity's sake here) will be:
<div class="page-index"><h1>Example has version FOOBAR</h1></div>
As you can see, the content from store state (in this case, version) is injected server-side before the page is rendered. This also works on Serverless + AWS Lambda lambda stack
If you need to store a lot of data from user's state (more than can be stored in a cookie) and need all of it to be populated server-side, I suggest you handle the state server-side (eg. store it in a DB, sessions_table), save eg. a JWT token in a cookie using vuex-persistedstate and use the JWT to get the correct session and then load the entire session data within asyncData of a component or within nuxtServerInit action of your Vuex, depending on your needs, and then do with it whatever you want.
This was one of the first results on google so, to add to the answer of @lukaVarga.
You don't have to fill the store manually, thats what this plugin does. Hence the name vuex-persistedstate, not vuex-to-cookie or whatever.
Following works as one would expect it to. Store is automatically restored, even before middlewares are triggered. No need to nuxtServerInit anything.
// nuxt.config.js
module.exports = {
...
plugins: [{ src: '~/plugins/vuex-persistedstate.js', ssr: true }],
...
}
// vuex-persistedstate.js
import createPersistedState from 'vuex-persistedstate'
import * as Cookies from 'js-cookie'
import cookie from 'cookie'
export default ({ store, isDev, req }) => {
createPersistedState({
key: 'mySiteCookie',
paths: [ 'myVuexModule' ],
storage: {
getItem: (key) => process.client ? Cookies.getJSON(key) : cookie.parse(req.headers.cookie||'')[key],
setItem: (key, value) => Cookies.set(key, value, { expires: 365, secure: !isDev }),
removeItem: (key) => Cookies.remove(key)
}
})(store)
// }
}
I am currently using
setTimeoutinside thecreatedmethod to guarantee that my store has been loaded before taking any action. However, it is not a good approach. I am looking for a way like a promise which theresolvewill be thrown when the state is loaded from the localStorage.
Im doing something like
computed: {
...mapState([
'storage'
])
},
mounted () {
const self = this
window.onNuxtReady(() => {
console.log(self.storage)
})
}
@lukaVarga it works if you set state directly in nuxtServerInit action. But if I have some boolean in state and user change it to false with button click by mutation and then do reload then still when I console.log it in nuxtServerInit it firstly shows default value which is true and then in template I can see it's false but it's still changing in the browser.
So in other words - if you change some state value in nuxtServerInit then browser receive already changed value but if you change the value in the browser and then perform refresh state at server have default values and synchronise in the browser.
So my thought was that it's not correctly/at all synchronising cookies and state in nuxtServerInit so I reached for this plugin cookie-universal-nuxt which basically allow me to get cookies on server from nuxt context.
@d0peCode the example I showed above stores the vuex state in the cookie that is persisted. Within nuxtServerInit which has access to the cookies via the req object from the nuxt context, you can parse the cookie and populate the store.
If the user changes something (by clicking on a button), that change will - if you wire everything up correctly - update the value of the cookie. Hence on next load, when you read the value from the cookie to set up the state within the nuxtServerInit, you'll get the updated value.
But yes, there is a bit of manual work to be done as you need to commit the mutations within the nuxtServerInit based on the value from the cookie, it doesn't work automatically.
@lukaVarga req.cookies seems to be undefined for me
@d0peCode you have to get req from context, like this
nuxtServerInit(store, { req }) {
if (req.cookies.vuex) {
const state = JSON.parse(req.cookies.vuex);
// store.commit('whatever', state.foo);
}
},
Yes of course, i have valid req object but there's no cookies in there.
There is something new about this? im still stuck in how to persist state when page reloads.
@dcruz1990 all solutions mentioned above are still working even with ssr, so it's probably your implementation that is not functioning right
Most helpful comment
This was one of the first results on google so, to add to the answer of @lukaVarga.
You don't have to fill the store manually, thats what this plugin does. Hence the name
vuex-persistedstate, notvuex-to-cookieor whatever.Following works as one would expect it to. Store is automatically restored, even before middlewares are triggered. No need to nuxtServerInit anything.