How to keep items in cart even after refresh using vuex - vue.js

The problems i am facing are -
My state become empty when I refresh the page
same occurs when i logout and then login
I am new to vuex and I want to build a functioning cart for my e-commerce site.
My cart store is as follows (ps. I have only made a very simple outline to check if it is working as desired):
let dayCare = window.localStorage.getItem('dayCare');
const state = {
dayCare: dayCare ? JSON.parse(dayCare) : [],
};
const getters = {
dayCareItems (state){
return state.dayCare
}
};
const actions = {
dayCareCart({commit}, dayCare){
let data = dayCare
commit('pushDaycareToCart', data)
return data
commit('saveCart')
},
};
const mutations = {
pushDaycareToCart(state, data){
return state.dayCare.push(data)
},
saveCart(state) {
window.localStorage.setItem('dayCare', JSON.stringify(state.dayCare));
}
};
export default {
state,
actions,
mutations,
getters
};
the data for my cart comes from :
<button type="submit" #click="dayCareCart(cartData)">Add To Cart</button>
<script>
import {mapGetters, mapActions} from 'vuex'
export default {
methods: {
...mapActions(["dayCareCart"]),
}
}
</script>
I want to know what i should add to retain the data for the logged in user

Why do you expect it to persist data? You aren't using any kind of database to store the data.

Use the vuex plugin vuex-persist. You can use it to persist data to localstorage or cookies while using everything awesome bout vuex

I figured out how to persist the cart. The save mutation should be called in the push to cart mutation
let dayCare = window.localStorage.getItem('dayCare');
const state = {
dayCare: dayCare ? JSON.parse(dayCare) :[],
};
const getters = {
dayCareItems (state){
return state.dayCare
}
};
const actions = {
dayCareCart({commit}, dayCare){
commit('pushDaycareToCart', dayCare)
},
};
const mutations = {
pushDaycareToCart(state, dayCare){
state.dayCare.push(dayCare)
this.commit('saveCart')
},
saveCart(state) {
window.localStorage.setItem('dayCare', JSON.stringify(state.dayCare));
},
};
export default {
state,
actions,
mutations,
getters
};

Related

Navigation component not getting re rendered with stage change in Vue3

When a user updates their username in the EditAccount component, the username is updated in the EditAccount component and in vuex store but not in the Navigation component even though stage change is updated to the new user name.
The problem is that the user is seing thier old user name in Navigation component and a updated user name in the EditAccount component and they don't match.
How can I Re render the Navigation component with the new user name?
Below is the the code for user the data in the Navigation component.
Store vuex: index.js
const store = createStore({
// strict: true,
state: {
user: null,
authIsReady: false,
//
// current category
playlistCategory: null,
},
//
getters: {
getUser(state) {
return state.user;
},
},
mutations: {
//
// update playlist category
updatePlaylistCategory(state, payload) {
state.playlistCategory = payload;
},
//
//
setUser(state, payload) {
state.user = payload;
},
//
setAuthIsReady(state, payload) {
state.authIsReady = payload;
},
//
},
actions: {
async editUser(context, payload) {
const { displayNewName, displayNewEmail } = payload;
await updateUserDetails(displayNewName, displayNewEmail);
// get current user
const responseUser = await user;
// set user state
context.commit('setUser', responseUser);
},
},
NavBar.vue
// vue3 and composition api
setup() {
// store
const store = useStore()
//
const { error, logout, isPending } = useLogout()
const router = useRouter()
//
// getters
const user = computed(() => {
return store.getters.getUser.displayName
})
Try adding set and get property:
const user = computed({
get: store.state.user,
set: (val) => store.state.user = val
});
Try using a getter instead acessing the value directly in the state
Getter for user:
export function getUser(state){
return state.getUser
}
and in the component import the getter like this:
<script>
import {mapGetters} from 'vuex'
export default {
computed: {
...mapGetters('*theStoreName*',['getUser'])
},
watch: {
getUser: function(){
//Should be possible to see when the getUser changes here
console.log(this.getUser)
}
}
}
</script>
Note: You have theStoreName for the store name you're using
Maybe the problem is that the store name is missing, or when you did store.state.user you're acessing the store? If it is it, then you should try to inform the variable you're trying to access, like If it is, like store.state.user.name, with the getter it would be: getUser.name

NuxtJS - Prevent fetch if data already exists in state?

I have a portfolio site built using NuxtJS and a headless Wordpress CMS. On several pages, I'm importing a mixin that looks like this:
import { mapActions, mapState } from 'vuex';
export default {
computed: {
...mapState({
galleries: state => state.portfolio.galleries[0],
})
},
methods: {
...mapActions('portfolio', ['fetchGalleries']),
},
async fetch() {
await this.fetchGalleries();
}
}
The Vuex module looks like this:
export const state = () => ({
galleries: [],
});
export const actions = {
async fetchGalleries({ commit }) {
let res = await this.$axios.$get(`${process.env.WP_API_URL}/wp/v2/media`);
const data = res.reduce((acc, item) => {
const { slug } = item.acf.category;
(acc[slug] || (acc[slug] = [])).push(item);
return acc;
}, {});
commit('setGalleries', data);
}
};
export const mutations = {
setGalleries(state, data) {
state.galleries.push(data);
}
};
fetch is being used in the mixin to return data from the api before page load. I noticed however that each time I navigate to a new page, it's running that same fetch and continually adding duplicate data to Vuex state.
How do I prevent fetch from running and continually adding duplicate data to my state if it already exists?
I'm not sure why this was tripping me up so much, but I figured out a very simple solution.
async fetch() {
if (this.galleries.length) return;
await this.fetchGalleries();
}
Just added a conditional return statement as the first line within the fetch function.

because reloading the page deletes the vuex data, having used mutations, vuejs?

Currently I have the following configuration in my vuex, what I do is through the userAuth action verify the user's role and assign it to a property of the state 'rol_user', using the UPDATEROL mutation. I execute this action when I log in so that the user's role is recorded in vuex.
here the vuex configuration:
import Vue from "vue";
import Vuex from "vuex";
import firebase from 'firebase';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
rol_user: ''
},
mutations: {
UPDATEROL: function (state, payload) {
state.rol_user = payload.rol_user;
}
},
actions: {
userAuth: async (context) =>{
let user = firebase.auth().currentUser;
if(user){
let user_info = await firebase.database().ref('users').child(user.uid).once('value');
let val_user = user_info.val();
console.log("USER AUTH - VUEX");
console.log(val_user.rol);
context.commit('UPDATEROL',{
rol_user: val_user.rol
});
}
}
}
});
It effectively assigns the user's role to the state property, rol_user.
The problem I have is when reloading the page. When I reload the page rol_user returns to its initial state, that is empty.
How can I do so that the value of the role is not lost even when reloading the page, but rather that it is changed to empty only until I log out
You need to use some sort of storage mechanism and check that storage everytime the app is first mounted. For example, you could store a session key in localStorage or just store the user state that you want to persist.
Note, I do not know what kind of data you are storing, I am assuming rol_user is an object, if it is a string, you do not need JSON serialization/deserialization as I've done in the example below:
import Vue from "vue";
import Vuex from "vuex";
import firebase from 'firebase';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
rol_user: ''
},
mutations: {
UPDATEROL: function (state, payload) {
state.rol_user = payload.rol_user;
localStorage && (localStorage.rol_user = JSON.stringify(state.rol_user));
//^ try to store the user role in localStorage
},
},
actions: {
userAuth: async (context) =>{
if(localStorage && localStorage.rol_user) {
//^ if it's in localStorage, log the user back in/update state to match what it is in localStorage
context.commit('UPDATEROL', { rol_user: JSON.parse(localStorage.rol_user)});
return;
}
let user = firebase.auth().currentUser;
if(user){
let user_info = await firebase.database().ref('users').child(user.uid).once('value');
let val_user = user_info.val();
console.log("USER AUTH - VUEX");
console.log(val_user.rol);
context.commit('UPDATEROL',{
rol_user: val_user.rol
});
}
}
}
});
You could also use Cookies (cookies are generally more common for this purpose, but localStorage also works just fine)

Vuex Getters Come Back as Undefined

I'm having a Vuex getters issue where the gitters return as undefined (in the Vue Dev Console and no errors are logged in the Chrome Dev Console).
If mapGetters() is commented out (like the example code below), the returned data is displayed on screen -> Providing if the user clicks into the link that has the data. The data will NOT display if the user enters the app directly at the point where the data should display.
There is a similar question but there is no accepted answer
Vue Console Logs:
STATE:
$_lgdHRS:Object
totHrs:129
GETTERS:
$_lgdHRS/totHrs:undefined
SomeContainer.vue
<script>
import store from '../../_store'
import { mapState, mapGetters } from 'vuex'
export default {
computed: {
...mapState('$_lgdHRS',{
totHrs : 'totHrs',
}),
// ...mapGetters('$_lgdHRS',{
// totHrs : 'totHrs',
// airHrs : 'airHrs',
// picHrs : 'picHrs',
// pmcHrs : 'pmcHrs',
// voHrs : 'voHrs',
// trngHrs : 'trngHrs'
// }),
},
created() {
this.storeKey = '$_lgdHRS';
if (!(this.storeKey in this.$store._modules.root._children)) {
this.$store.registerModule(this.storeKey, store);
}
},
mounted() {
this.$store.dispatch('$_lgdHRS/getLogSummary');
},
}
</script>
<template>
<total-summary :hours="totHrs" />
</template>
state.js
export const state = {
totHrs: Number,
}
getters.js
const totHrs = state => state.totHrs;
export default {
totHrs,
};
mutations.js
const
TOTAL_HRS_UPDATED = (state, totHrs) => {
state.totHrs = +totHrs;
};
export default {
TOTAL_HRS_UPDATED,
};
Most probably because you have just displatched the request in mounted and before the data is set into the state variable your component is displayed.
Hence you can trying using async await in mounted as well as in store actions.
Do refer the following link and check the last example in this.
https://vuex.vuejs.org/guide/actions.html
The problem was that I was nesting my variables as I usually would in other frameworks.
Example:
// NESTED VARS
const r = response
totHrs = r.total,
airHrs = r.airborne,
picHrs = r.PIC,
pmcHrs = r.PMC,
voHrs = r.VO,
trngHrs = r.training;
// CHANGE TO:
const r = response
const totHrs = r.total
const airHrs = r.airborne
const picHrs = r.PIC
const pmcHrs = r.PMC
const voHrs = r.VO
const trngHrs = r.training
I don't know enough to why but your input would be greatly appreciated in the comments.

VUEJS + VUEX State reset everytime dispatch action

Everytime i dispatch action in vuex it remove my old state of users and add dispatch actions to playlist. I don't know what is problem so sharing screenshot you may understand in image what i am trying to say.
Thing is when application start it works fine with default values but when i add dispatch with some button or event then it remove user state object from vuex but keep playlist with new item in it. I know when dispatch playlist refresh vuex object but how to keep user object same time ?
This is action i added and works fine but i have to do this every time i add something or if other actions then i have to apply same thing.
Any idea i don't have to put user dispatch every time ?
addSongToList() {
playlist.dispatch('addSong', { title: "Beside Me",
mp3: "http://dl.jatt.link/lq.jatt.link/cdn8/1a40cff114c5ee39b75dd3813c3f29dd/cdlzv/Ni%20Mainu-(Mr-Jatt.com).mp3",
});
store.dispatch('updateUser', this.getUser );
}
Thanks
This is my playlist.js store file :
import Vuex from 'vuex'
let state = {
playerList: []
};
let getters = {
getPlaylist: state => {
return state.playerList
}
};
let actions = {
addSong: ({commit}, song) => {
commit('ADD_SONG_TO_PLAYLIST', song)
}
};
let mutations = {
ADD_SONG_TO_PLAYLIST(state, song) {
state.playerList.push(song)
}
};
let playlist = new Vuex.Store({
state,
getters,
mutations,
actions,
});
global.playlist = playlist;
export default playlist
This is user.js
import Vuex from 'vuex'
import playlist from './playlist'
let state = {
user: {}
};
let getters = {
getUser: state => {
return state.user
}
};
let actions = {
updateUser: ({commit}, user) => {
commit('ADD_USER', user)
},
deleteUser: ({commit}) => {
commit('DELETE_USER')
}
};
let mutations = {
ADD_USER(state, user) {
state.user = user
},
DELETE_USER(state) {
state.user = null
}
};
export default new Vuex.Store({
state,
getters,
actions,
modules: {
playlist
},
mutations,
})