importing store to a vuejs nuxt project - vue.js

I'm trying to write a simple plugin for my Vue.js(Nuxt) project. I came across this post Adding Mutations to Vuex store as part of Vue Plugin but still unable to get it working.
Here is my application structure.
~ is root
~/plugins/HTTP/index.js
~/plugins/HTTP/_store/ => index.js, actions.js, getters.js, mutations.js
~/plugins/HTTP/_api/ => index.js
**Global Store**
~/store/index.js
~/store/modules/
~/store/modules/testing => index.js, actions.js, getters.js, mutations.js
in my ~/plugins/HTTP/index.js, I have the following code
import Vue from 'vue';
import store from '~/store';
const HTTP = {
install(vue, { store }){ // Now you plugin depend on store
if(!store){
throw new Error('Please provide vuex plugin.')
}
// register your own vuex module
store.registerModule({store})
}
}
export default HTTP;
Vue.use(HTTP)
In my ~/store/index.js I have the following code:
import Vuex from 'vuex'
import testingModule from './modules/testing'
const state = () => {
return new Vuex.Store({
modules:{
testing: testingModule
}
})
}
export default state
When I try to run it, it gives me the following message:
Cannot destructure property `store` of 'undefined' or 'null'.
What did I do wrong here?

You aren't passing any properties so the error is correct. You need pass in an options object when you tell it to use. It can be empty, but it needs an object.
import Vue from 'vue';
import store from '~/store';
const HTTP = {
install(vue, { store }){ // Now you plugin depend on store
if(!store){
throw new Error('Please provide vuex plugin.')
}
// register your own vuex module
store.registerModule({store})
}
}
export default HTTP;
Vue.use(HTTP, {}) // <---------- Empty object to avoid allow destructuring.

Related

Using the NuxtJS Strapi Module in Vuex

I am using #nuxt/strapi as a wrapper around Strapi for NuxtJS.
For Vuex inside Nuxt I am using the namespaced modules mode, so my structure looks as an example like this:
store
├── user.js
├── posts.js
└── index.js
In a Vue project I would import Vue, Vuex, maybe Axios and then create a store instance const store = new Vuex.Store(storeOptions) and dispatch my initial actions or make some API calls from inside store/index.js.
Example for index.js in a vue project:
import Vuex from 'vuex';
import Vue from 'vue';
import user from './modules/user'
import posts from './modules/posts'
Vue.use(Vuex);
const storeOptions = { ... }
const store = new Vuex.Store(storeOptions)
if (user) {
...
store.dispatch('startPageLoading', 'store');
store.commit('SET_USER', user);
await store.dispatch("getSomeData");
...
}
But in a Nuxt project the store and the strapi instances already were created in root_project/.nuxt/.... So what is the best way to use $strapi and $store inside store/index.js? Neither $strapi or $store are available in store/index.js
there is this nuxtServerInit action that gets executed on the server side after you open / refresh page.
You can only do it in index.js file
This is how your index.js could look like:
//index.js
export const state = () => ({
someState: false
})
export const mutations = {
SOME_MUTATION(state, payload) {
...
}
}
export const actions = {
SOME_ACTION({ state, commit }, payload) {
...
},
nuxtServerInit({ commit }, { $strapi }){
//do here something on the server side...
}
}
The documentation says if you added the strapi module to your project, you should be able to access it from the context. The context is the second argument from nuxtServerInit
Thats it. This is how a store could look like, nothing fancy.
You could dispatch / commit something from any component with
this.$store.commit("SOME_MUTATION")
They say its global available with this.$strapi
This module globally injects $strapi instance, meaning that you can access it anywhere using this.$strapi. For plugins, asyncData, fetch, nuxtServerInit and Middleware, you can access it from context.$strapi.

Theory: Axios Calls (Specifically for VueJS)

On component mount(), Axios fetches information from the back end. On a production site, where the user is going back and forth between routes it would be inefficient to make the same call again and again when the data is already in state.
How do the pros design their VueJS apps so that unnecessary Axios calls are not made?
Thank you,
If the data is central to your application and being stored in Vuex (assuming that's what you mean by "state"), why not just load it where you initialise your store?
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'wherever'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
centralData: {}
},
mutations: {
setCentralData (state, centralData) {
state.centralData = centralData
}
},
actions: {
async loadCentralData ({ commit }) {
const { data } = await axios.get('/backend')
commit('setCentralData', data)
}
}
}
// initialise
export const init = store.dispatch('loadCentralData')
export default store
If you need to wait for the dispatch to complete before (for example) mounting your root Vue instance, you can use the init promise
import Vue from 'vue'
import router from 'path/to/router'
import store, { init } from 'path/to/store'
init.then(() => {
new Vue({
store,
router,
// etc
}).$mount('#app')
})
You can import and use the init promise anywhere in order to wait for the data to load.

VueX/VueJS: call mutation from another file

I'm searching the way to call a mutation on a store from another file which is not a single file component.
This file is responsible to manage the axios configuration to be able to make some API calls. I managed some interceptors and i would like to call a mutation to change state of the notification store to display a notification in UI.
import axios from "axios";
import i18n from './i18n';
import Vue from 'vue';
// Define global param object for notification options
const options = {
type: "danger"
};
// Create global Axios instance for CTC Backends API calls
const instance = axios.create({
baseURL: process.env.VUE_APP_BACKEND_URL,
});
// Define interceptor for responses to handle certain API responses
instance.interceptors.response.use(res => {
console.log('axiosBackend::ResponseInterceptor()', res);
return res;
}, error => {
if (!error.response) {
Vue.$store.commit("SHOW_NOTIFICATION", {
text: i18n.t("serverError"),
type: 'error'
});
}
return Promise.reject(error.response);
});
export default instance;
If I understand your problem properly. You have to import the store instance and use it to call the mutation.
import store from '#/store'
...
store.commit("SHOW_NOTIFICATION", {
...
import {store} from './store';
store.commit("SHOW_NOTIFICATION", paylo )

Not able to access i18 plugin from mutation in classic mode store in Nuxt application

I'm trying to implement Vuex i18n package within my Nuxt application. In my nuxt.conf.js file in plugins array I have:
{
src: '#/plugins/i18n.js',
ssr: false
},
plugins/i18n.js file is:
import Vue from "vue";
import vuexI18n from "vuex-i18n/dist/vuex-i18n.umd.js";
import toEnglish from "../translations/toEnglish";
import toSpanish from "./../translations/toSpanish";
import toGerman from "./../translations/toGerman";
export default ({ store }) => {
Vue.use(
vuexI18n.plugin,
store,
{
onTranslationNotFound: function (locale, key) {
console.warn(`vuex-i18n :: Key '${key}' not found for locale '${locale}'`)
}
}
);
// register the locales
Vue.i18n.add('en', toEnglish);
Vue.i18n.add('de', toGerman);
Vue.i18n.add('es', toSpanish);
// Set the start locale to use
Vue.i18n.set('de');
Vue.i18n.fallback('en');
}
Last thing is my store. I'm using classic mode of vuex store in Nuxt:
import Vuex from "vuex";
const store = () => {
return new Vuex.Store({
state: () => ({
currentLanguage: ''
}),
mutations: {
changeLang(state, response) {
if (response) {
console.log(this);
state.currentLanguage = response;
this.i18n.set(response);
}
}
}
})
};
export default store;
As you can see in store file in mutation I'm trying to access i18n plugin with this keyword. Unfortunetally in print error in console:
TypeError: Cannot read property 'set' of undefined
this which I consoled also inside mutation is:
I changed this.i18n.set(response); to state.i18n.locale = response; inside my mutation and now it seems working.
For some reason when I call this mutation my video.js player refresh. I will try to find out why.

Vue.js / Mixins - Is there a way to get the global mixin-object outside of the vue component?

I am new with Vue.js
I am using Vue.js 2.4.4.
I have created the global mixin in my app.js file:
...
import router from './router'
...(some imports and plugins definitions)
Vue.use(VeeValidate);
Vue.component(VuePassword);
...
Vue.mixin({
data: function(){
return {
get auth(){
return Auth;
}
}
}
});
const app = new Vue({
el: '#root',
template: `<app></app>`,
components: { App },
router
});
This mixin imports some Auth object with validation methods e.t.c which needed to be in every component.
All of my components can check this mixin and it's working fine.
But I need to check the auth state after every route request, and I want to use my currently existing mixin, so I am trying to make something like this in my router.js file:
import Vue from 'vue'
import VueRouter from 'vue-router'
...
Vue.use(VueRouter);
const router = new VueRouter({
routes:[
...
]
});
router.beforeEach((to, from, next) => {
if(to.meta.requiresAuth) {
if(...call to mixin method) {
next();
} else {
next('/');
}
} else {
next();
}
});
export default router
Question:
Is there a way to get the global mixin object and change it's inner values or can you please give some small advise or example what is the right solution to this kind of tasks?
Or should I use the plugins instead of mixins?
I would rather create a seperate file for auth and not make it a mixin. Then using Vue.use() which will set auth on the vue object.
A sample of what the files might look like:
auth.js
export default function(Vue) {
Vue.auth = {
// do your auth logic
}
}
Then in your main js file
main.js
import Auth from './auth.js'
Vue.use(Auth);
Then you should be able to use Vue.auth
Another option would be keep using the mixin and pass the value to a store (like vuex) or create your own if your project is small...