How do I enable namespacing on an imported VueX module? - javascript

I'm using a helper file to import VueX modules:
const requireModule = require.context('.', false, /\.store\.js$/)
const modules = {}
requireModule.keys().forEach(filename => {
const moduleName = filename
.replace(/(\.\/|\.store\.js)/g, '')
.replace(/^\w/, c => c.toUpperCase())
modules[moduleName] = requireModule(filename).default || requireModule(filename)
})
export default modules
This lives in #/store/modules/index.js and is imported by #/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules'
Vue.use(Vuex)
export default new Vuex.Store({
modules,
actions: {
reset({commit}) {
Object.keys(modules).forEach(moduleName => {
commit(`${moduleName}/RESET`);
})
}
}
})
Imported in to Vue: #/main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Works great for all of my store modules! Each of which are namespaced:
const initialState = () => ({})
const state = initialState()
const mutations = {
RESET(state) {
const newState = initialState();
Object.keys(newState).forEach(key => {
state[key] = newState[key]
});
}
}
const getters = {}
const actions = {}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Now, I'm trying to import a package as a state module. Which I don't have any experience with. This might seem silly... but I'm not sure how to inject the namespace enablement into the package importation in #/store/modules/Auth.store.js:
import AmazonCognitoVuexModule from 'amazon-cognito-vuex-module';
const cognito = new AmazonCognitoVuexModule({
region: process.env.VUE_APP_COGNITO_REGION,
userPoolId: process.env.VUE_APP_COGNITO_USERPOOL_ID,
clientId: process.env.VUE_APP_COGNITO_CLIENT_ID,
})
export default cognito
So when I try to call the imported store module's actions with $store.dispatch('Auth/...') they're not found... because they're not namespaced. I want to namespace this module "Auth". I bet I'm overlooking something really simple. Any help appreciated.

My first try would be (based on the docs of this package on NPM):
// source: https://www.npmjs.com/package/amazon-cognito-vuex-module
const store = new Vuex.Store({
modules: {
cognito: new AmazonCognitoVuexModule({
region: '<region>',
userPoolId: '<user pool id>',
clientId: '<client id>'
})
}
});
The code above shows that you can import it as a module (they named it cognito, you want auth - that should make no difference; I use the naming in the official docs). So you need to update your code, like this:
import Vue from 'vue'
import Vuex from 'vuex'
import modules from './modules'
import cognito from './path/to/cognito'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
...modules,
cognito,
},
actions: {
reset({commit}) {
Object.keys(modules).forEach(moduleName => {
commit(`${moduleName}/RESET`);
})
}
}
})
I'm not sure this works, but this would be my first try :)

Related

Can't use Vuex to display data

I am a new .net+vuejs learner and i'm using
this project template for vuejs
I'm trying to use vuex in my project to display countries data from database but it doesn't work
main.js
import 'bootstrap/dist/css/bootstrap.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
index.js
import { createApp } from "vue";
import App from "./App.vue";
import Vuex from "vuex";
import countries from "./module/countries/countries";
createApp(App).use(Vuex);
export default new Vuex.Store({
modules: {
countries: countries
}
});
store file
import axios from "axios";
const state = {
countries:[]
};
const countries = {
async getCountries({ commit }, payload) {
const result = await axios.get("Pho/GetCountries");
return result.data;
}
};
export default {
namespaced: true,
state,
mutations,
countries,
getters
}
my component
<script>
import axios from 'axios'
import swal from 'sweetalert';
export default {
name: "Home",
data() {
return {
countries: [],
}
},
methods: {
getCountries: async function () {
this.countries = await this.$store.dispatch("countries/getCountries");
}
},
mounted() {
this.getCountries();
}
}
</script>
ERROR: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dispatch')
i tried to import store to my main.js like this
import 'bootstrap/dist/css/bootstrap.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './index.js'
createApp(App).use(router, store).mount('#app')
but the app doesn't ever lauch
It is not good practice to call APIs from storage files. Use vuex storage for only storage, use mixins(recommended) or component methods for sending API. I will show a simple approach to managing vuex storage!
Storage File: index.js
import Vue from 'vue'
Vuex from 'vuex'
import router from '../router/index'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
countries:[]
},
getters: {},
mutations: {
countriesChanger(state, payload) {
state.countries = payload;
},
},
actions: {},
});
Component File: MyComponent.vue
<template>
<li v-for="country in countries">
{{country}}
</li>
</template>
<script>
export default {
name: "Home",
data() {
return {
countries: [],
}
},
mounted() {
this.getCountries(); // assume this function calls to your API
},
watch: {
"$store.state.countries": function () {
// Listens when countries in storage updated
this.countries = this.$store.state.countries;
}
}
</script>
To change vuex storage item (to update countries) , use mutations after getting data from your API:
this.$store.commit("countriesChanger", countriesFromAPI);
That's it!

Vuex Uncaught Error: [vuex] getters should be function despite getter being a function

Encountering a problem with Vuex 4.0.2 where it throws an uncaught error indicating that a specific getter should be a function, even though it is indeed a function.
Error: Uncaught Error: [vuex] getters should be function but "getters.teamsWithPlayers" is [].
Vue 3.2.31
store/index.js
const getters = {
teamsWithPlayers (state) {
if (state.game.teams === undefined) {
return state.game.teams
}
const teamsWithPlayersList = []
state.game.teams.forEach(function (team) {
const individualScores = []
team.players = state.game.players.filter(player => team.name === player.team)
team.players.forEach(function (player) {
individualScores.push(player.score)
})
team.score = individualScores.reduce(function (a, b) {
return a + b
}, 0)
teamsWithPlayersList.push(team)
})
return teamsWithPlayersList
}
}
export default createStore({
namespaced: true,
state,
mutations,
actions,
getters
})
~
Found the issue was with the creation of the Vue app in main.js. As I was upgrading an existing project from Vue 2 to Vue 3, there was a reference to the old Vuex object instantiation that I did not catch.
The incorrect main.js.
import { createApp } from 'vue'
import Vuex from 'vuex'
import App from './App.vue'
import router from './router'
import store from '#/store'
import '#/assets/styles/reveal_theme.scss'
const vuexStore = new Vuex.Store(store)
const app = createApp(App).use(router).use(vuexStore)
app.mount('#app')
This is fixed by removing the references to the old Vuex.Store.
Corrected main.js:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from '#/store'
const app = createApp(App).use(router).use(store)
app.mount('#app')

Couldn't access state in vuex 4

I'm using vuex v4 with composition api. The problem is I couldn't access store states in components but I can see them in vue-devtools. When I wanna access store state it gave me undefined.
store/index.ts:
import { InjectionKey } from "vue";
import {
createStore,
createLogger,
Store,
useStore as vuexUseStore,
} from "vuex";
import { ConfigStateType } from "./config/state";
import config from "./config";
export enum ModuleTypes {
CONFIG = "CONFIG",
}
export interface StateInterface {
config: ConfigStateType;
}
export const key: InjectionKey<Store<StateInterface>> = Symbol();
export const store = createStore<StateInterface>({
modules: {
[ModuleTypes.CONFIG]: config,
},
strict: debug,
});
export function useStore() {
return vuexUseStore(key);
}
vue js main.ts:
import { store, key } from "./store";
createApp(App).use(store, key).use(router).mount("#app");
In my component:
import { useStore } from "#/store";
setup() {
const store = useStore();
const recaptchaSiteKey = computed(
() => store.state.config.googlerecaptcha_site_key
);
return {
recaptchaSiteKey
}
}
always recaptchaSiteKey returns undefined, but in vue-devtools states are filled.
vuex devtool:

vue.js : error unknown action type?

I created my store store/user.js
export const state = () => ({
user: {},
});
export const mutations = {
};
export const actions = {
AUTH ({commit},{email, password}){
console.log('email, password =', email, password)
}
};
export const getters = {};
component:
<template>
<form #submit.prevent="AUTH(model)">
<input type="text" required v-model.lazy = "model.email">
<input type="password" required v-model.lazy = "model.password" >
</template>
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
model:{
email:" " ,
password:" "
}
}
},
methods: {
...mapActions(['AUTH']),
}
}
In my component , I am trying to execute a vuex action from a module, but I am getting an error, even if this action is defined :
unknown action type: AUTH,
I don't have any idey about problem.
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user.js'
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
user
}
})
You need to use createNamespacedHelpers:
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('users')
Binding helpers with namespace
Otherwise, the mapping helpers need the full module namespace:
...mapActions([
'users/AUTH'
])
// if you are only using one module in the component
...mapActions('users', [
'AUTH'
])
Nuxt
You're mixing classic and modules mode. When using modules mode, Nuxt creates the store instance from the index.js file. You simply export the state, getters, mutations and actions. State should be exported as a function:
export const state = () => ({
foo: 0,
bar: 1
})
Any file within the store directory will be considered a module and Nuxt will automatically register it as a namespaced module.
- store
-- index.js // the store
-- users.js // module 'users'
-- foo.js // module 'foo'
The users module looks otherwise correct.
Make the following changes to your component:
// template
<form #submit.prevent="submitForm">
// script
methods: {
...mapActions({
auth: 'users/AUTH'
}),
submitForm () {
this.auth(this.model)
}
}

Why is setting Vue.http for vue-resource ignored?

I'm using Vue.js 2.3.3, Vue Resource 1.3.3, Vue Router 2.5.3, and I'm trying to set up Vue-Auth. I keep getting a console error, however, that says auth.js?b7de:487 Error (#websanova/vue-auth): vue-resource.1.x.js : Vue.http must be set.. I'm setting Vue.http in main.js, but vue-resource is not picking it up for some reason.
main.js:
import Vue from 'vue'
import Actions from 'actions'
import App from './App'
Vue.use(Actions, {
locales: ['en', 'zh', 'fr']
})
Vue.http.options.root = 'https://api.example.com'
new Vue({
render: h => h(App),
watch: {
lang: function (val) {
Vue.config.lang = val
}
}
}).$mount('#app')
actions/index.js
import VueResource from 'vue-resource'
import Router from 'actions/router'
import I18n from 'actions/i18n'
export default {
install (Vue, options) {
Vue.use(Router)
Vue.use(I18n, options.locales)
Vue.use(require('#websanova/vue-auth'), {
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x'),
auth: require('#websanova/vue-auth/drivers/auth/bearer'),
http: require('#websanova/vue-auth/drivers/http/vue-resource.1.x')
})
}
}
And if I add Vue.use(VueResource) to actions/index.js right below Vue.use(Router), I get a new error: Error (#websanova/vue-auth): vue-router.2.x.js : Vue.router must be set.
On the other hand, if I move Vue.http.options.root = 'https://api.example.com' to right below the import statements, I get yet another error: Uncaught TypeError: Cannot read property 'options' of undefined
You need to import 'vue-resource' in to your main.js file to get ride of this errors:
import Vue from 'vue'
import VueResource from 'vue-resource';
import Actions from 'actions'
import App from './App'
Vue.use(Actions, {
locales: ['en', 'zh', 'fr']
})
Vue.use(VueResource)
Vue.http.options.root = 'https://api.example.com'
new Vue({
render: h => h(App),
watch: {
lang: function (val) {
Vue.config.lang = val
}
}
}).$mount('#app')
Using axios and not vue-resource this is a working setup for me:
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueRouter)
Vue.use(VueAxios, axios)
Vue.router = new VueRouter({
// Your routes.
})
Vue.use(require('#websanova/vue-auth'), {
auth: require('#websanova/vue-auth/drivers/auth/bearer.js'),
http: require('#websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x.js'),
})
App.router = Vue.router
new Vue(App).$mount('#app')
For more guidance you can refer to this great tutorial: https://codeburst.io/api-authentication-in-laravel-vue-spa-using-jwt-auth-d8251b3632e0

Categories