Nuxt.js with vuex-persist - persisted state not available in asyncData upon page refresh - vuex

Upon first page refresh, the asyncData function is not able to fetch the persisted state. When I follow another NuxtLink, and go back to this page, while the state is not mutated in the meantime, the data is there. This means the persisted state is not available on the server side at first load/refresh. LocalStorage is where I choose to persist the relevant state items.
A pages component that uses asyncData:
asyncData({ app, params, store }) {
//its not available upon first refresh, but is after following a random nuxtlink and going back
const cartProducts = store.getters.getCartProducts
},
store/index.js is straightforward. Unfortunately, the state is completely empty in asyncData upon first page refresh.
getCartProducts(state) {
return state.cart.products
},
vuex-persist.js imported properly with mode 'client' as recommended in the Github Readme
import VuexPersistence from 'vuex-persist'
/** https://github.com/championswimmer/vuex-persist#tips-for-nuxt */
export default ({ store }) => {
window.onNuxtReady(() => {
new VuexPersistence({
key: 'cartStorage'
/* your options */
}).plugin(store)
})
}
How can I make sure the relevant store terms from local storage are persisted before asyncData is called?

You can't do this. Its impossible. There is no localstorage on server. And asyncData executed on server on first load/refresh. So there is no way to get data from in asyncData from localstorage on server even theoretically.

Related

Nuxtjs store undefined in middleware on refresh

I'm using nuxt js for my web app, I need to keep the store when I refresh the page, even in middleware or the page itself.
I'm using vuex-persistedstate;
import createPersistedState from "vuex-persistedstate";
export default ({ store }) => {
if (process.client) {
window.onNuxtReady(() => {
createPersistedState({})(store);
});
}
};
One of the solutions that I tried is to use cookies in the store, but my data is very huge and I need it in the local storage.
I think it's something related to SSR or server middleware, I tried a lot to figure out how to solve it, but nth is working.
It is impossible because we are not able to access localStorage when component is rendering on the server side. You should either turn off ssr to use localStorage or try to reduce the size of your data to put it in cookies.

Values disappearing after refresh

Once I log in I set username and loggedIn value, I import the values to my component, it works but after refreshing the page this goes back to original value, why is this happening?
I didn't have this issue when Using vuex in vue 2. Do I really have to store this data in localStorage? Wtf.
const loggedIn = ref(false);
const userName = ref('');
export default function useAuth() {
const login = async ({ email, password }) => {
try {
const result = await AuthService.login({ email: email, password: password });
userName.value = result.data.nick;
loggedIn.value = true;
}
}
return {login, loggedIn, userName}
}
A browser does not automatically store the current memory of a JavaScript application. On a page refresh, the complete page is re-rendered and a new "application" is loaded. You can influence this behavior when you store your state on the back-end site (push relevant data to back-end via API and store it there e.g. in a database) or you can store your state in the browser's storage. This can be as a cookie, session/local storage and IndexedDB. Depending on your needs, you can then retrieve the relevant state from the back-end or your locally stored data on page load. If you are using Vuex, there are plugins which allow you to do this automatically. You can still use Vuex with Vue3 (use useStore() instead of this.$store).
If you are using just the plain composition API, the in-memory variables won't be saved. You can, however, easily watch the variables and set the values to the local store by yourself. See e.g. this example where a new variable is created with the value from the local storage (on page load), a watcher is defined where the value is going to be set to the storage and then finally the variable is returned from this module.

Fetching global api data in nuxt

I'm starting Nuxt project and I have to fetch basic data from my backend.
for example language dictionary or some data for leftbar and etc.
in Vue I can just call everything I need in App.vue and save it in vuex and then use whenever I want, but with Nuxt every page is different and I'm curious where should i call this global data api calls.
I'm guessing I have to create middleware and call actions if data is not loaded already or there is better solution?
You mention it's global data and you're using universal mode- I think you're looking for nuxtServerInit(). This store action runs once on the server, before created, mounted hooks etc. You can use it to populate your store with data that your components (including pages) rely on.
Take a look at the docs.
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}

Load async data into the vuex store when Nuxt app loads

I am trialling a project in Nuxt. Liking it so far except I am a little confused as to how to load data from an external async service so that it is available in Vuex from the very first route.
I have tried adding middleware on the default layout to dispatch the store action but I do not see the service being called straight away. Only when I navigate deeper into the routes do I see the action dispatched.
I did something similar in a standard Vue project and added the created method to the App.vue.
Is there a similar way in Nuxt?
What you need is called a fetch.
The fetch method, if set, is called every time before loading the component (only for page components). It will be called server-side once (on the first request to the Nuxt app) and client-side when navigating to further routes.
Warning: You don't have access of the component instance through this inside fetch because it is called before initiating the component.
async fetch({ store }) {
await store.dispatch('your-action')
}
If you need parameter:
async fetch({ store, params }) {
await store.dispatch('your-action', params.id)
}
I gave an example of id. The name of the parameter depends on the name of your page.
_id => params.id
_slug => parmas.slug
...

Handling browser history with React-Redux

We are using React-Redux in your application. The problem is that we want to do undo and redo Redux state based on user navigation from browser buttons. Assume user is in page A and user browses couple of other pages and then he navigates to page A, for instance. Now If user presses back button in the browser, he'll go back to page A but here we want to have the previous instance of state which application had when user the page A.
Is there a centralized approach to solve this problem that doesn't need to handle the state manipulation manually.
What you are trying to achieve is a default behavior of React-Redux. If you are not trying to dispatch some actions, which manipulates specific component's state, when a route changes, it should persist its old state, without any additional functionality.
So my guess is that you are dispatching some actions when new route loads the component. How it could be dealt with this (e.g not to fetch resources from rest API once it existed, which finally caused to manipulate component) is here: https://github.com/reactjs/redux/blob/master/examples/async/src/actions/index.js#L35
const shouldFetchPosts = (state, reddit) => {
const posts = state.postsByReddit[reddit]
if (!posts) {
return true
}
if (posts.isFetching) {
return false
}
return posts.didInvalidate
}
export const fetchPostsIfNeeded = reddit => (dispatch, getState) => {
if (shouldFetchPosts(getState(), reddit)) {
return dispatch(fetchPosts(reddit))
}
}
So what this is doing is that it won't pass a new data into component once route changes if it already exists, so the old data/state stays there. You can abstract this functions more to make it easily reusable for all the other components.