Vuex data just show once then won't display after reloading - vue.js

why my json data display just only once and after reloading the page it won't show again.
Did I miss something here?
import axios from "axios";
const store = {
careers: []
};
const getters = {
allCareers: (state) => state.careers
};
const mutations = {
RETRIEVE_CAREERS: (state, career) => (state.careers = career),
};
const actions = {
async careers({ commit }) {
try {
const response = await axios.get('http://localhost:9001/career/jobs/');
commit('RETRIEVE_CAREERS', response.data);
} catch (err) {
console.log(err);
}
},
};
export default {
store,
getters,
mutations,
actions
}
and in my component I do this:
import { mapActions, mapGetters } from "vuex";
export default {
computed: {
...mapGetters([
"allCareers"
/* more getters here if necessary */
])
},
methods: {
...mapActions(["careers"])
},
created() {
this.careers();
}
};
and in template I just do this:
<template>
<section>
<v-card>
{{allCareers}}
</v-card>
</section>
</template>
Why it will show only once but won't show after reloading the page?

I don't see anywhere that you "persist" the fetched data. Vuex does not persist the data across reloads, it acts as an in-memory storage
You still have to persist your data to local storage of some sorts like localStorage or indexedDB.
Here is a simple solution:
const store = {
careers: JSON.parse(localStorage.getItem('careers') || '[]');
};
const mutations = {
RETRIEVE_CAREERS: (state, career) => {
state.careers = career;
localStorage.setItem('careers', JSON.stringify(career));
}
};

Related

Nuxt js / Vuex Cannot get state variables on components which is set by nuxtServerInit

I am trying to get the state variable on components which is set by the nuxtServerInit Axios by get method.
store/state.js
export default () => ({
siteData: null
})
store/mutations.js
import initialState from './state'
const mutations = {
SET_SITE_DATA (state, value) {
state.siteData = {
site_title: value.site_title,
logo: value.logo
}
}
}
export default {
...mutations
}
store/getters.js
const getters = {
siteDetails: state => state.siteData
}
export default {
...getters
}
store/actions.js
const actions = {
async nuxtServerInit ({ commit, dispatch }, ctx) {
try {
const host = ctx.req.headers.host
const res = await this.$axios.post('/vendors/oauth/domain/configuration', { domain: host })
commit('SET_SITE_DATA', res.data.data.site_data)
} catch (err) {
console.error(err)
}
},
export default {
...actions
}
}
store/index.js
import Vuex from 'vuex'
import mutations from './mutations'
import getters from './getters'
import actions from './actions'
import state from './state'
const store = () => {
return new Vuex.Store({
state,
getters,
mutations,
actions
})
}
export default store
Here I set SET_SITE_DATA mutation which set siteData state.
components/Header.vue
<template>
<section class="header sticky-top">
<client-only>
{{ siteDetails }}
{{ $store.getters }}
{ logo }}
</client-only>
</section>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['siteDetails']),
logo () {
console.log(this.$store.state.siteData)
return this.$store.state.siteData
}
}
}
</script>
Console
I don't know what is happening here. You can see I have consoled the values. So when I reload the page I can get the values but after few seconds all values reset to the null. I want to set those values globally so can access them all over the site. I don't want to call API every time a page changes so I used nuxtServerInit so can set values globally when the page reloads once and can access them.

vue.js move method from .vue to vuex store

Scenario:
in user.js I have:
import * as mutationTypes from "../mutation-types";
import {user} from "./user_data";
export const state = {
user: user
...
}
export const getters = {
user: (state) => state.user,
...
};
export const mutations = {
[mutationTypes.SET_USER]: (state, payload) => {
state.user=payload;
},
...
);
export const actions = {
setUser: ({ commit }, payload) => {
commit(mutationTypes.SET_USER, payload);
},
...
);
export default {
state,
getters,
mutations,
actions,
};
now I want to move a method used in several pages from the .vue pages to this store page:
so I added to user.js actions the following:
getUser: async ({ commit }) =>{
this.user.loading=true;
try{
const res = await this.$http.post('/ajax/settings/settings_read.php');
if (res.data.errorid=='0')
{
let payload=res.data.user;
commit(mutationTypes.SET_USER, payload);
}
else
{
this.$router.push('/auth/login').catch(() => {});
}
} catch(e)
{
console.log(e);
}
this.user.loading=false;
},
and in .vue pages (actually I tried may different solutions adding async/await in several places)
import { mapActions } from "vuex";
...
created(){
this.$store.dispatch("getUser");
},
but does not work.
Can suggest the right way to move a method to vuex store?
Looks like this.user is reference to user in your state, hence
this.user.loading=true;
would change the state outside the mutation.

from same axios to different components, VueJS

Okay, I have two different components and each of those get Axios response. But I don't want to fetch data in each component separate. That's is not right, and it cause components run separate...
Updated 3
I did some changes on the code, but still having some problems. I am doing axios call with Vuex in Store.js and import it into my component. it's like below.
This is my store.js component;
import Vue from "vue";
import Vuex from "vuex";
var actions = _buildActions();
var modules = {};
var mutations = _buildMutations();
const state = {
storedData: []
};
Vue.use(Vuex);
const getters = {
storedData: function(state) {
return state.storedData;
}
};
function _buildActions() {
return {
fetchData({ commit }) {
axios
.get("/ajax")
.then(response => {
commit("SET_DATA", response.data);
})
.catch(error => {
commit("SET_ERROR", error);
});
}
};
}
function _buildMutations() {
return {
SET_DATA(state, payload) {
console.log("payload", payload);
const postData = payload.filter(post => post.userId == 1);
state.storedData = postData;
}
};
}
export default new Vuex.Store({
actions: actions,
modules: modules,
mutations: mutations,
state: state,
getters
});
Now importing it into Average component.
import store from './Store.js';
export default {
name:'average',
data(){
return{
avg:"",
storedData: [],
}
},
mounted () {
console.log(this.$store)
this.$store.dispatch('fetchDatas')
this.storedData = this.$store.dispatch('fetchData')
},
methods: {
avgArray: function (region) {
const sum = arr => arr.reduce((a,c) => (a += c),0);
const avg = arr => sum(arr) / arr.length;
return avg(region);
},
},
computed: {
mapGetters(["storedData"])
groupedPricesByRegion () {
return this.storedData.reduce((acc, obj) => {
var key = obj.region;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj.m2_price);
return acc;
}, {});
},
averagesByRegion () {
let arr = [];
Object.entries(this.groupedPricesByRegion)
.forEach(([key, value]) => {
arr.push({ [key]: Math.round(this.avgArray(value)) });
});
return arr;
},
}
}
I can see the data stored in the console. But there are errors too. I can't properly pass the data in myComponent
https://i.stack.imgur.com/J6mlV.png
if you don't want use vuex to distrib data maybe you can try eventBus, when you get data form the axios respose #emit the event and in another component #on this event
The issue is that
To resolve the error you're getting, Below are the steps.
Import your store file inside the file where your Vue Instance is initialized.
// Assuming your store file is at the same level
import store from './store';
Inside your, Add store object inside your Vue Instance
function initApp(appNode) {
new Vue({
el: appNode,
router: Router,
store // ES6 sytax
});
}
There you go, you can now access your store from any component.
UPDATE: For Second Error
Instead of changing data inside your component, change it inside mutation in the store because you do not want to write the same login in other components where the same method is used.
Hence,
computed: {
...mapGetters(["storedData"]),
anotherFunction() {
// Function implementation.
}
}
Inside your mutation set the data.
SET_DATA(state, payload) {
console.log("payload", payload);
state.storedData = payload;
}
Inside getters, you can perform what you were performing inside your computed properties.
storedData: function(state) {
const postData = state.storedData.filter(post => post.userId == 1);
return postData;
}
Vuex Official docs
Here is the working codesandbox
Hope this helps!

currentUser not getting set with Vuex

I added some code to my vue project so I can save the state of a user - which is whether he is logged in or not. If the state is not null, I want to display the navbar and footer. I added all the vuex import statements. I am using an axios call to the db which returns a json response. response.data comes back as true/false. If true, I redirect the user to the main page. Then I create a user object called currentUser, but I'm not sure what to base it on, so it is getting set to null. I need to use the state in a few places throughout my app, but it is not getting set. Please someone help. Thanks in advance. (code is below)
User.js:
import JwtDecode from 'jwt-decode'
export default class User {
static from (token) {
try {
let obj = JwtDecode(token)
return new User(obj)
} catch (_) {
return null
}
}
constructor ({username}) {
this.username = username
}
}
App.vue:
<template>
<div id="app">
<template v-if="currentUser">
<Navbar></Navbar>
</template>
<div class="container-fluid">
<router-view></router-view>
<template v-if="currentUser">
<Foot></Foot>
</template>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Navbar from '#/components/Navbar'
import Foot from '#/components/Foot'
export default {
name: 'App',
components: {
Navbar,
Foot
},
computed: {
...mapGetters({ currentUser: 'currentUser' })
},
mutation_types.js:
export const LOGIN = 'LOGIN'
export const LOGOUT = 'LOGOUT'
auth.js:
/* global localStorage */
import User from '#/models/User'
import * as MutationTypes from './mutation_types'
const state = {
user: User.from(localStorage.token)
}
const mutations = {
[MutationTypes.LOGIN] (state) {
state.user = User.from(localStorage.token)
},
[MutationTypes.LOGOUT] (state) {
state.user = null
}
}
const getters = {
currentUser (state) {
return state.user
}
}
const actions = {
login ({ commit }) {
commit(MutationTypes.LOGIN)
},
logout ({ commit }) {
commit(MutationTypes.LOGOUT)
}
}
export default {
state,
mutations,
getters,
actions
}
The user store should only set the default state. AFter making request to validate user. You should use actions and mutations to set the user state. Call the action via store.dispatch("user/login", user) where you return new User(obj).
let obj = JwtDecode(token)
const user = new User(obj)
store.dispatch("user/login", user)
const actions = {
login ({ commit }, userObject) {
commit(MutationTypes.LOGIN, userObject)
},
logout ({ commit }) {
commit(MutationTypes.LOGOUT)
}
}
const mutations = {
[MutationTypes.LOGIN] (state, user) {
state.user = user;
},
[MutationTypes.LOGOUT] (state) {
state.user = null
}
}
On a other note, you have dumb getters. Meaning they just return the state. You can rather call the user object directly out of state. Use getters when you want to modify the return value before returning it.
I took a little look and it seems you use '=' instead of Vue.set() to set your state variable.
Refer to the answer : vuex - is it possible to directly change state, even if not recommended?

vuex store getters not working in a component

Can anyone see why this wouldn't work please,
Trying to use vuex store to manage my axios requests and transfer to a component as follows:
In my vuex store module I have the following
import axios from "axios";
export const state = () => ({
cases: [],
})
export const mutations = {
listCases (state, cases) {
state.cases = cases;
},
}
export const actions = {
loadCases ({ commit, context }) {
return axios.get('http')
.then(res => {
const convertCases = []
for (const key in res.data) {
convertCases.push({ ...res.data[key], id: key })
}
commit('listCases', convertCases)
})
.catch(e => context.error(e));
},
export const getters = {
// return the state
cases(state) {
return state.cases
}
}
I checked amd my axios request is returning my results as expected and passing to the mutation
In my component I have
import { mapMutations, mapGetters, mapActions } from 'vuex'
export default {
created () {
this.$store.dispatch('cases/loadCases');
},
computed: {
...mapGetters ({
cases: 'cases/cases'
})
},
</script>
Now i assumed based on what I've learnt that i could call with
and this would return my items.
but i get an error cases is not defined,
Anyone abe to tell me my error please
Many Thanks
Take a look here: https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection
You may be able to make it reactive this way:
export const mutations = {
listCases (state, cases) {
state.cases = [];
cases.forEach((c) => {
state.cases.push(c);
});
},
}