How to dispatch store actions in namespaced modules ( NuxtJS)? - vue.js

I have made lots of research and since keywords are always similar I cannot find a correct way of usage store modules in nuxtjs. I will shorten the codes to make it readable. In my nuxtjs application, I am trying to reach my vuex modules in my home.page but instead I get
pages/index.vue
TypeError
Cannot read property 'then' of undefined
created() {
this.$store.dispatch('articles/fetchIndexArticles')
.then(() => this.$store.dispatch('videolessons/fetchIndexVideolessons'))
.then(() => {
While creating modules first in the store folder i have created an index.js file:
import Vuex from "vuex";
import articles from "./modules/articles";
// ...
import videolessons from "./modules/videolessons";
const debug = process.env_NODE_ENV !== 'production';
export const store = new Vuex.Store({
modules: {
articles,
books,
members,
pages,
status,
user,
videolessons,
},
strict: debug,
plugins: [],
})
and basically my modules are similar to my articles module:
const getDefaultState = () => {
return {
indexArticles: [],
}
}
const state = getDefaultState()
const getters = {
indexArticles (state) {
return state.indexArticles
},
}
const mutations = {
fetchStart (state) {
state.loading = true
},
fetchEnd (state) {
state.loading = false
},
setIndexArticles (state, pArticles) {
state.indexArticles = pArticles
state.errors = {}
},
setError (state, errors) {
state.errors = errors
},
resetState (state) {
Object.assign(state, getDefaultState())
}
}
const actions = {
// ...
async fetchIndexArticles ({ commit }) {
try {
const response = await articlesService.fetchIndexArticles()
commit('fetchStart')
commit('setIndexArticles', response.data)
commit('fetchEnd')
return response
} catch (error) {
commit('setError', error)
this._vm.$q.loading.hide()
}
},
...
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
and in my index page:
<script>
import store from '../store/'
export default {
computed: {
indexarticles() {
return this.$store.getters['articles/indexArticles'];
}
},
created() {
this.$store.dispatch('articles/fetchIndexArticles')
.then(() => this.$store.dispatch('videolessons/fetchIndexVideolessons'))
...
.then(() => {
this.isLoading = false;
});
}
};
</script>
<template>...</template>
can you help to correct my store modules?
Thanks
ps:
videolessons.js
const getDefaultState = () => {
return {
indexvideolessons: [],
}
}
const state = getDefaultState()
const getters = {
indexVideolessons (state) {
return state.indexvideolessons
},
}
const mutations = {
setIndexVideolessons (state, pVideolessons) {
state.indexvideolessons = pVideolessons
state.errors = {}
},
}
const actions = {
async fetchIndexVideolessons ({ commit, dispatch }) {
try {
const response = await videolessonsService.fetchIndexVideolessons()
commit('setIndexVideolessons', response.data)
return response
} catch (error) {
commit('setError', error)
}
},
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}

Related

Unable to update state in redux when using #reduxjs/toolkit

I currently started learning redux. My code was working perfectly with core redux, then I tried out #reduxjs/toolkit and now I'm unable to access the function to change the state in the store. Here is my code of reducer.
const seasonEdits = createSlice({
name: "seasons",
initialState: [],
reducers: {
addSeason(state, action) {
state.push(action.payload);
console.log("this here");
},
removeSeason(state, action) {
state.filter((season) => season.id !== action.payload);
},
markComplete(state, action) {
state.map((season) => {
if (season.id == action.payload) season.isWatched = !season.isWatched;
});
},
},
});
export const { addSeason, removeSeason, markComplete } = seasonEdits.actions;
export default seasonEdits.reducer;
and my store.js file
import { configureStore } from "#reduxjs/toolkit";
import seasonReducer from "./reducer";
export default store = configureStore({
reducer: {
seasons: seasonReducer,
},
});
and the add.js file which has add functionality. Calling a handleSubmit function which is creating an object and adding it to an array which is the state in store.
const handleSubmit = async () => {
try {
if (!name || !totalNoSeason) {
return alert("Please add both fields");
}
const seasonToAdd = {
id: shortid.generate(),
name,
totalNoSeason,
isWatched: false,
};
addSeason(seasonToAdd);
navigation.navigate("Home");
} catch (error) {
console.log(error);
}
};
const mapDispatchToProps = (dispatch) => {
return {
addSeason: (data) => dispatch(addSeason(data)),
};
};
Add.propTypes = {
addSeason: propTypes.func.isRequired,
};
export default connect(null, mapDispatchToProps)(Add);
The issue is that array.map() and array.filter() return new arrays! Right now your reducers are calling those functions, and then just throwing away the new arrays:
removeSeason(state, action) {
// The return value is thrown away and ignored!
state.filter((season) => season.id !== action.payload);
},
You need to return the new value:
removeSeason(state, action) {
// Now RTK will see the new return value
return state.filter((season) => season.id !== action.payload);
},
See https://redux-toolkit.js.org/usage/immer-reducers#resetting-and-replacing-state for more details.

Vuex is not mutating the state

I am trying to switch authenticated from false to true, a property in the state, It's not working.
My codes from store.js
state() {
return{
authenticated : false,
user : {}
}
},
getters : {
authenticated(state){
return state.authenticated
}
},
mutations : {
set_authenticated(state, value){
return state.authenticated = value
}
},
My updated code from login.vue (script)
data() {
return {
allerrors : [],
success : false,
data: {
email : "",
password : ""
}
}
},
methods : {
login: function() {
this.$store
.dispatch("login", this.data)
.then(response => {
this.allerrors = [],
this.success = true,
this.data = {}
alert(response.data)
})
.catch((error) => {
this.allerrors = error.response.data.error
this.success = false
alert(allerrors)
})
},
My updated action is :
async login({ commit }, data) {
await axios.post('login', data)
.then(response => {
commit('set_authenticated',true);
})
.catch((error) => {
this.allerrors = error.response.data.error
this.success = false
})
}
There are a few problems here:
First, if that is the full code for your store.js file, then you are missing the call to createStore() (for Vue 3) or new Vuex.Store() (for Vue 2)
import { createStore } from 'vuex'
// Create a new store instance.
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
Source
The second problem is that you shouldn't be committing mutations from your Single File Components. The typical flow is:
Components dispatch actions
Actions commit mutations
Mutations update state
You're trying to commit a mutation directly from the component.
You need to add an action to your store.js
async login({ commit }, userData) {
await axios.post('login', userData)
.then(response => {
commit('set_authenticated',true);
})
.catch((error) => {
this.allerrors = error.response.data.error
this.success = false
})
}
Mutation:
mutations : {
set_authenticated(state, value){
state.authenticated = value
}
},
Then your Login.vue would change to something like:
methods: {
login: function() {
this.$store
.dispatch("login", { userData })
.then(() => )) // whatever you want to do here.
.catch(err => console.error(err));
}
}
mutations shouldn't have a return statement. it should be like this
mutations : {
set_authenticated(state, value){
state.authenticated = value
}
},

On component created hook call Action to fetch data from database and store it in state and then call Getter to get the data

So basically I have this component and I am using its created hook to fetch data using vue-resource and VUEX action, storing that data in store and right after that trying to get that data using VUEX getter but I am unable to do so. Any work around or I am doing something wrong. I am new to Vue!
Component:
import { mapActions } from 'vuex';
import { mapGetters } from 'vuex';
export default {
components: {
categoryHeader: CategoryHeader,
categoryFooter: CategoryFooter,
AddCategory
},
data() {
return {
openCatAdd: false,
categories: [],
pagination: []
}
},
methods: {
...mapActions([
'getCategories'
]),
...mapGetters([
'allCategories'
])
},
created() {
this.getCategories(1);
this.categories = this.allCategories();
// console.log(this.categories);
}
};
Store:
import Vue from "vue";
const state = {
categories: [],
};
const mutations = {
setCategories: (state, payload) => {
state.categories = payload;
}
};
const actions = {
getCategories: ({commit}, payload) => {
Vue.http.get('categories?page='+payload)
.then(response => {
return response.json();
})
.then(data => {
commit('setCategories', data.data);
}, error => {
console.log(error);
})
}
}
const getters = {
allCategories: state => {
console.log(state.categories);
return state.categories;
}
};
export default {
state,
mutations,
actions,
getters
};

How to keep user logged in between page refreshes in FastAPI and Vue

I am new to vue.js, I have a simple web application(Vue frontend connected to a FastAPI backend) that a user can create an account and login, All of this works so far but when I refresh the page the user is logged out.
And console show an error:
Uncaught (in promise) TypeError: Cannot read property '$store' of undefined
What am I doing wrong? How to keep user logged in even after page refresh. Can anyone please help me?? thanks
store/index.js
import Vuex from 'vuex';
import Vue from 'vue';
import createPersistedState from "vuex-persistedstate";
import auth from './modules/auth';
// Load Vuex
Vue.use(Vuex);
// Create store
const store = new Vuex.Store({
modules: {
auth
},
plugins: [createPersistedState()]
});
export default store
store/modules/auth.js
import { postUserLogInAPI } from "../../service/apis.js";
const state = {
token: "",
expiration: Date.now(),
username: ""
};
const getters = {
getToken: (state) => state.token,
getUsername: (state) => state.username,
getFullname: (state) => state.fullname,
isAuthenticated: (state) => state.token.length > 0 && state.expiration > Date.now()
};
const actions = {
async LogIn({ commit }, model) {
await postUserLogInAPI(model).then(function (response) {
if (response.status == 200) {
commit("LogIn", response.data)
}
})
},
async LogOut({ commit }) {
commit('LogOut')
}
};
const mutations = {
LogIn(state, data) {
state.username = data.username
state.fullname = data.fullname
state.token = data.token
state.expiration = new Date(data.expiration)
},
LogOut(state) {
state.username = ""
state.fullname = ""
state.token = ""
state.expiration = Date.now();
},
};
export default {
state,
getters,
actions,
mutations
};
service/http.js
import axios from 'axios'
import { Loading, Message } from 'element-ui'
import router from '../router/index.js'
import store from '../store';
let loading
function startLoading() {
loading = Loading.service({
lock: true,
text: 'Loading....',
background: 'rgba(0, 0, 0, 0.7)'
})
}
function endLoading() {
loading.close()
}
axios.defaults.withCredentials = true
axios.defaults.baseURL = 'http://0.0.0.0:80/';
axios.interceptors.request.use(
(confing) => {
startLoading()
if (store.getters.isAuthenticated) {
confing.headers.Authorization = "Bearer " + store.getters.getToken
}
return confing
},
(error) => {
return Promise.reject(error)
}
)
axios.interceptors.response.use(
(response) => {
endLoading()
return response
},
(error) => {
Message.error(error.response.data)
endLoading()
const { status } = error.response
if (status === 401) {
Message.error('Please Login')
this.$store.dispatch('LogOut')
router.push('/login')
}
return Promise.reject(error)
}
)
export default axios
components/NavBar.vue
<script>
export default {
name: "NavBar",
computed: {
isLoggedIn: function () {
return this.$store.getters.isAuthenticated;
},
username: function () {
return this.$store.getters.getUsername;
},
fullname: function () {
return this.$store.getters.getFullname;
},
},
methods: {
async logout() {
await this.$store.dispatch("LogOut");
this.$router.push("/login");
},
},
};
</script>

Nuxt nuxtServerInit now being called

I am trying to setup the store/index.js in Nuxt and don't understand why nuxtServerInit is not being called. I have added the console.log to test it out, but it doesn't seem to work or output the log.
import Vuex from 'vuex'
import axios from 'axios'
const createStore = () => {
return new Vuex.Store({
state: {
loadedPosts: []
},
mutations: {
setPosts(state, posts) {
state.loadedPosts = posts;
}
},
actions: {
nuxtServerInit(vuexContext, context) {
console.log('Init works!');
return axios.get("<firebase.link>")
.then(res => {
const postsArray = []
for (const key in res.data) {
postsArray.push({...res.data[key], id: key})
}
vuexContext.commit('setPosts', postsArray)
})
.catch(e => context.error(e))
},
setPosts(vuexContext, posts) {
vuexContext.commit('setPosts', posts)
}
},
getters: {
loadedPosts(state) {
console.log("Here we go",state.loadedPosts);
return state.loadedPosts
}
}
})
}
export default createStore
Fixed it!
The app was in spa mode instead of universal.