How to get the latest updated data on VueJs? - vue.js

I'm new to Vuejs and still figuring out how to get the latest updated data.
app.js - preload the data after calling 'global/checkUserSignedIn'
import Vue from 'vue'
import axios from 'axios'
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
import App from 'components/app-root'
import { mapGetters, mapActions } from 'vuex'
Vue.prototype.$http = axios
sync(store, router)
const app = new Vue({
store,
router,
...App,
created() {
this.preload()
},
methods: {
preload: function () {
this.$store.dispatch('global/checkUserSignedIn')
}
}
})
export { app, router, store }
global.js (a vuex store)
/// actions, mutations here
const actions = {
checkUserSignedIn({ commit, state }) {
commonApi.isUserSignedIn().then(function (data) {
state.usersignedin = data
})
},
}
const getters = {
isUserSignedIn: state=>state.usersignedin
}
export default {
state,
getters,
actions,
mutations,
namespaced: true
}
On a component, I call:
export default {
computed: {
...mapGetters('global', ['isUserSignedIn']),
},
watch: {
isUserSignedIn: function (newVal, oldVal) {
if (newVal !== undefined) {
console.log('ok, correct result')
}
}
},
updated() {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
console.log('updated: ' + this.isUserSignedIn)
})
},
created() {
console.log('created :' this.isUserSignedIn)
}
}
}
On both Updated and Created, I don't get the last updated data isUserSignedIn which is True if a user has been logged in though if I put {{isUserSignedIn }} on a template, it shows correctly.
Is there any way to get it to work other than having to use a Watcher here.
Updated: Maybe using Watcher is the only way to get the lastest updated data.

Related

Pinia getter does not filter state (options API)

I have a pinia store I am using with a vue component, with the options API. I have a getter in my pinia store that is supposed doing some basic filtering of items. However, the getter just returns what is in state without any of the filtering applied.
My component:
<template>
<DetailsWrapper :filteredDetails="filteredDetails"
</template>
<script>
import {mapState, } from 'pinia';
export default {
components: DetailsWrapper,
computed: {
...mapState(useDetailsStore, {
filteredDetails: store => store.filteredDetails,
},
};
</script>
In my pinia store I have:
import axios from 'axios';
import { defineStore } from 'pinia';
const useDetailsStore = defineStore('details', {
getters: {
filteredDetails: state => {
const productDetails = state.product && state.product.details;
productDetails.forEach(detail => {
detail.values.filter(detail => detail.isOnline && detail.isDisplayable
});
return productDetails
},
});
export default useDetailsStore
The end result is just that everything in productDetails is returned -- nothing is filtered out, even though there are definitely values to be filtered.
If anyone could provide any guidance it would be much appreciated!
You can try like this:
import axios from 'axios';
import { defineStore } from 'pinia';
const useDetailsStore = defineStore('details', {
getters:
{
filteredDetails(state)
{
return (state.product?.details || []).map(product => ({
...product,
values: product.values.filter(val => val.isOnline && val.isDisplayable),
});
},
});
export default useDetailsStore;

Vue3 - Persisting state with Page refresh

I have just started using Vue3, and am trying to use vuex to manage state. when using Vue2 I would call the store each time the app loads like this:
// mains.js
import VueRouter from "vue-router";
import Vuex from "vuex";
import router from "./routes";
window.Vue = require('vue').default;
Vue.use(VueRouter);
Vue.use(VueMoment);
Vue.use(Vuex);
const store = new Vuex.Store(storeDefinition);
const app = new Vue({
el: '#app',
router,
store,
components: {
"index": Index
},
async created() {
this.$store.dispatch("loadStoredState");
this.$store.dispatch("loadUser");
},
});
This is my vuex store that defines state, mutations and actions for vuex:
// store.js
import { isLoggedIn, logOut } from "./shared/utils/auth";
export default {
state: {
isLoggedIn: false,
user: {}
},
mutations: {
setUser(state, payload) {
state.user = payload;
},
setLoggedIn(state, payload) {
state.isLoggedIn = payload;
}
},
actions: {
loadStoredState(context) {
context.commit("setLoggedIn", isLoggedIn());
},
async loadUser({ commit, dispatch }) {
if (isLoggedIn()) {
try {
const user = (await axios.get("/user")).data;
commit("setUser", user);
commit("setLoggedIn", true);
} catch (error) {
dispatch("logout");
}
}
},
logout({ commit }) {
commit("setUser", {});
commit("setLoggedIn", false);
logOut();
}
},
getters: {}
}
This file manages a cookie for local storage that stores a boolean value for isLoggedIn:
// auth.js
export function isLoggedIn() {
return localStorage.getItem("isLoggedIn") == 'true';
}
export function logIn() {
localStorage.setItem("isLoggedIn", true);
}
export function logOut() {
localStorage.setItem("isLoggedIn", false);
}
But in Vue3 I am creating the main.js file like this:
// mains.js
const { createApp } = require('vue')
import Index from './Index.vue'
import createRouter from './router'
import { createStore } from 'vuex'
import storeDefinition from "./store";
const store = createStore(storeDefinition)
createApp(Index)
.use(createRouter())
.use(store)
.mount('#app')
How can I add the two calls to manage the store to the createApp function?
You can add the created hook to the root component by using the extends option with the component definition:
// main.js
import { createApp } from 'vue'
import Index from './Index.vue'
import createRouter from './router'
import { createStore } from 'vuex'
import storeDefinition from './store'
const store = createStore(storeDefinition)
createApp({
extends: Index,
created() {
this.$store.dispatch('loadStoredState')
this.$store.dispatch('loadUser')
},
})
.use(createRouter())
.use(store)
.mount('#app')
demo

IONIC + Vue.js not working getters in VUEX

Hello developers I'm working with Ionic and Vue+Vuex in this app, but eventually, I can't access my state from my getters for some reason.
As usually the management state is settled for that purpose with actions getters, mutations, and state.
import { createStore } from "vuex";
const urlLogin = "http://localhost:3006/auth";
const urlUser = "http://localhost:3006/user";
const store = createStore({
state() {
return {
userRegisteredState: false,
allUsersState: [],
};
},
mutations: {
commit_get_all_users(state, payload) {
console.log(payload);
return (state.allUsersState = payload);
},
},
getters: {
getterGetAllUsers(state) {
console.log(state);//checking all state (See image )
console.log(state.allUsersState)//checking only the item I want to consume from state (See image )
return state.allUsersState;
},
},
actions: {
//=================================================================
//============================================================
async getAllUsers({ commit }) {
fetch(`${urlUser}/get/all/users`, {
method: "GET",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "http://localhost:8100",
},
})
.then((result) => {
return result.json();
})
.then((result) => {
console.log(result);
commit("commit_get_all_users", result);
})
.catch((error) => {
console.log(error);
error;
});
},
},
});
export default store;
then on my component , in this case that one referring to get all users I set this logic:
<template>
...some tags...
</template>
<script>
import { mapActions, mapGetters } from "vuex";
export default {
name: "AllUsersComponent",
data() {
return {
allUsers: [],
};
},
methods: {
...mapActions(["getAllUsers"]),
getAllUsersFront() {
this.$store.dispatch("getAllUsers");
},
...some methods....
},
computed: {
...mapGetters(["getterGetAllUsers"]),
getterGetAllUsersFunction() {
console.log(this.$store.getters.getterGetAllUsers);
return this.$store.getters.getterGetAllUsers;
},
},
async mounted() {
this.getAllUsersFront();
},
created() {
this.getAllUsersFront();
this.getterGetAllUsersFunction;
console.log(this.getterGetAllUsersFunction);
},
watch: {},
};
</script>
<style>
</style>
On my main.js file store is imported according to IONC in this way
import { createApp } from "vue";
import './gapi.js'
import App from "./App.vue";
import router from "./router";
import store from "./store/index"; //importando vuex
import loginComponentTag from "./components/Login";
import allUsersComponentTag from "./components/all-users-component"
// import GoogleSignInButton from 'vue-google-signin-button-directive'
import { IonicVue } from "#ionic/vue";
/* Core CSS required for Ionic components to work properly */
import "#ionic/vue/css/core.css";
/* Basic CSS for apps built with Ionic */
import "#ionic/vue/css/normalize.css";
import "#ionic/vue/css/structure.css";
import "#ionic/vue/css/typography.css";
/* Optional CSS utils that can be commented out */
import "#ionic/vue/css/padding.css";
import "#ionic/vue/css/float-elements.css";
import "#ionic/vue/css/text-alignment.css";
import "#ionic/vue/css/text-transformation.css";
import "#ionic/vue/css/flex-utils.css";
import "#ionic/vue/css/display.css";
/* Theme variables */
import "./theme/variables.css";
const app = createApp(App)
.use(IonicVue)
.use(store)
.use(router)
app.component("LoginComponent", loginComponentTag);
app.component("AllUsersComponent",allUsersComponentTag)
router.isReady().then(() => {
app.mount("#app");
});
And my vue.config.js is settled in this way:
module.exports = {
devServer: {
proxy: "http://localhost:8100",
},
};
I checked my logs and eventually.
Literally, the situation is that despite having my state populated with data, unless I retrieve the whole state, I can't retrieve a particular item from it, cause the response is nothing.
Is there any configuration I'm omitting in this process I need to have in mind?

mapActions not returning action from module

I am trying to add the Actions I created in my Vuex module to the Methods of my component.
My component "HomePage.vue" looks like this
import { PlusIcon } from "vue-feather-icons";
import TaskItem from "../TaskItem";
import moment from "moment";
import { mapGetters, mapActions } from "vuex";
export default {
name: "home-page",
components: {
PlusIcon,
TaskItem,
},
methods: {
...mapActions(['fetchTasks'])
},
computed: mapGetters(['allTasks']),
created() {
setInterval(() => {
document.getElementById("time").innerHTML = moment().format("h:mm:ss a");
}, 1000);
},
};
My Vuex module "tasks.js" looks like this
import fs from 'fs'
const state = {
tasks: []
}
const getters = {
allTasks: (state) => state.tasks
}
const actions = {
fetchTasks({commit}) {
let rawdata = fs.readFileSync('../backend/tasks.json')
console.log(JSON.parse(rawdata))
commit('setTasks', JSON.parse(rawdata))
}
}
const mutations = {
setTasks: (state, passedTasks) => (state.tasks.push(passedTasks))
}
export default {
state,
getters,
actions,
mutations,
}
When attempting to use this.fetchTasks() in created(), nothing happens.
When console logging this.fetchTasks() it returns as undefined
Considering your tasks is a module of your vuex store, you should call your mapActions, mapGetters this way :
methods: {
...mapActions('tasks', ['fetchTasks'])
},
computed: {
...mapGetters('tasks', ['allTasks'])
},

Access the state of store or getters? _WEBPACK_IMPORTED_MODULE_3__store___.a.dispatch is not a function

I am trying to verify if the user is authenticated to be able to give access to the route that is directed otherwise redirect to the login route, the problem is that I do not know how to execute the fetchUser action from my beforeEach. In other words, I can't access my getter from the router script.
store.js
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
export default {
state: {
isLoggedIn: !!localStorage.getItem("token"),
user_data : localStorage.getItem("user_data"),
},
getters ,
mutations,
actions
}
routes/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import routes from './rutas';
import store from '../store/';
const router = new VueRouter({
mode : 'history',
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({path: '/login'})
}
else {
store.dispatch('fetchUser') // Line error
next()
}
}
else {
next() // make sure to always call next()!
}
})
getters.js
export default {
isLoggedIn: state => {
return state.isLoggedIn
},
user_name : state =>{
if(! _.isEmpty(this.user_data))
return JSON.parse(state.user_data).name
return '';
},
isEmptyUser : state =>{
return _.isEmpty(this.user_data);
},
isAdmin: state => {
if(! _.isEmpty(this.user_data)) return state.user_data.nivel===1
return false;
}
}
actions.js
export default {
/* more methods*/
, async fetchUser({ commit }) {
return await axios.post('/api/auth/me')
.then(res => {
setTimeout(() => {
localStorage.setItem("user_data", JSON.stringify(res.data));
Promise.resolve(res.data);
}, 1000);
},
error => {
Promise.reject(error);
});
}
This returns error in console:
_WEBPACK_IMPORTED_MODULE_3__store___.a.dispatch is not a function
How can I do or the approach is the wrong one and I should not access actions directly?
The problem is your store is not the actual store object, it is just the object used to generate it.
A solution is to have the file export the real store:
import Vue from 'vue';
import Vuex from 'vuex';
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
Vue.use(Vuex); // added here
export default new Vuex.Store({ // changed here
state: {
isLoggedIn: !!localStorage.getItem("token"),
user_data : localStorage.getItem("user_data"),
},
getters ,
mutations,
actions
}) // changed here
Now your router code would work.
What you must be aware as well is that somewhere, probably in your main.js, you had the store being initialized like above. For example:
import store from '../store/';
new Vue({
store: new Vuex.Store(store),
// ...
})
Now you must remove that initialization and use the store directly:
import store from '../store/';
new Vue({
store: store, // or simply store
// ...
})
And all should be good.