Vuejs and Webpack: Why is store undefined in child components - vue.js

I am using Vuejs with Webpack.
Here's store.js:
import Vuex from "vuex";
export default new Vuex.Store({
state: {
count : 0
},
mutations: {
increment (state) {
state.count++
}
}
});
Here is my app.js:
"use strict";
import Vue from 'vue';
window.Vue = Vue;
import MyComponent from './MyComponent.vue';
import store from './store.js';
window.App = new Vue({
el : '#my-app',
store,
components : {
'my-component' : MyComponent
}
});
Here is the script from MyComponent.vue:
export default {
computed : {
count() {
return this.$store.state.count;
}
},
mounted() {
console.log(this.$store)
}
}
Any reference to this.$store in my component is undefined. Why?

You need to install the Vuex plugin somewhere to allow Vue components to access the store. As Pavan noted, to do this you must include the following lines somewhere (in your app's index.js, in your store.js etc) before you create your Vue instance:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
This tells Vue what to do with the store instance when you create the instance, which will make it available under this.$store in your components. This also ensures that Vuex also knows how to interact with Vue. Without it, you will not be able to use Vue and Vuex together properly.
Regarding your later answer, you can export the store instance just fine, and import it into your index.js, router config etc. For example:
store.js:
import Vuex from "Vuex";
export default new Vuex.Store({ /* store config */ });
MyComponent.vue's <script> block:
export default {
mounted() {
console.log(this.$store); // will log the store instance
}
}
index.js:
import Vue from "vue";
import Vuex from "vuex";
import store from "./store";
import MyComponent from "./components/MyComponent.vue";
Vue.use(Vuex);
const app = new Vue({
el: "#my-app"
store,
components: { MyComponent },
// any other options as needed
});

You should add these 2 lines in your store.js
import Vue from "vue";
Vue.use(Vuex);
There's no way you can instantiate store without actually saying the second statement above. So, you need to import Vue in your store.js

OK, so the reason I wanted to go down this path was to separate the store code from the rest of the application.
I have managed to do that by exporting a default object from store.js, where that object is only the configuration for the store (i.e. not a store instance). I then instantiate the store in my app.js, using the imported configuration.
I will leave this answer open for a few days in case someone wants to provide a way to export/import the instance itself.

Related

sometimes when I use createApp(App).use(...)... everything disappear

I was trying to use vuex in my vue project.When I directly use the store everything is fine.But when I try to put the store in module then use it,everything just gone.
Also,if I import router from my router.js and use it ,everything will gone.
Super confused about it.
the way I directly use it
import a from "./store/modudel/a"
the way I put in module
// main.js
import store from "./store/index";
createApp(App)
.use(store)
.mount("#app");
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import a from './module/a';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
a
}
});
Your store/index.js contains code specific to Vue 2, but your main.js is for Vue 3. This code should be causing linter errors in the dev terminal or runtime errors in the browser console.
Assuming you have a Vue 3 project with Vuex 4, the equivalent store code would be:
// store/index.js
import { createStore } from 'vuex';
import a from './module/a';
export default createStore({
modules: {
a
}
});

How can I set up moment.js in the vuetify?

I using vuetify : https://vuetifyjs.com/en/
I want to use moment.js. So I read this reference : https://www.npmjs.com/package/vue-moment
I had run npm install vue-moment
I'm still confused to put this script Vue.use(require('vue-moment'));
In the vuetify, there exist two file : main.js and index.js
main.js like this :
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/index'
import './registerServiceWorker'
import vuetify from './plugins/vuetify'
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')
index.js like this :
import Vue from 'vue';
import Vuex from 'vuex';
import dataStore from './modules/data-store';
import createLogger from "vuex/dist/logger";
Vue.use(Vuex);
const debug = process.env.VUE_APP_DEBUG !== "production";
export default new Vuex.Store({
modules: {
dataStore
},
strict: debug,
plugins: debug ? [createLogger()] : []
});
where do i put Vue.use(require('vue-moment'));?
I try to put it in the main.js, but if i call my vue component, there exist error : ReferenceError: moment is not defined
My vue component like this :
<template>
...
</template>
<script>
export default {
mounted() {
let a = moment("2012-02", "YYYY-MM").daysInMonth();
console.log(a)
}
};
</script>
I found this at the bottom of the vue-moment npm page
vue-moment attaches the momentjs instance to your Vue app as
this.$moment.
This allows you to call the static methods momentjs provides.
So you should be able to use your original configuration of vue-moment and do this in your mounted() method
mounted() {
let a = this.$moment("2012-02", "YYYY-MM").daysInMonth();
console.log(a)
}
notice this.$moment
And for the set up of vue-moment you should place this in your main.js file
main.js
Vue.use(require('vue-moment'))
=========================================================================
GLOBAL
If you want to use moment with Vue globally you can create an Instance Proprety
main.js
import moment from 'moment'
Vue.prototype.moment = moment
In your component you then call this.moment in your methods or computed properties. In your mounted section it would look like this
mounted() {
let a = this.moment("2012-02", "YYYY-MM").daysInMonth();
console.log(a)
}
COMPONENT
If you just want to use moment in a component you can include directly like this
<script>
import moment from 'moment'
export default {
mounted(){
let a = moment("2012-02", "YYYY-MM").daysInMonth();
console.log(a)
}
}
</script>

Can't access this.$store (vuex) in any child component after basic installation

So I am totally new to vuex. I carefully install the vuex to my vue app but I can't acess the this.$store in any of my child component.
I have also read more than 10 questions ask the same thing and I did a lot of changes, tried lots of times. Since I thought I did everything right and it still doesn't work. I finally decide to come here and ask. I will put my own codes below:
file structure (only related files):
|---main.js
|---store.js
|---App.vue
|---components
main.js:
import '#babel/polyfill'
import Vue from 'vue'
import App from './App.vue'
import './plugins/vuetify'
import './plugins/vue-resource'
import { store } from './store';
require('../node_modules/ol/ol.css');
Vue.config.productionTip = false
fetch('static/App_Config.json')
.then(function (response) {
return response.json().then(function (AppConfig) {
Vue.prototype.$AppConfig = AppConfig;
new Vue({
store,
render: h => h(App)
}).$mount('#app')
});
})
store.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex, {
});
export const store = new Vuex.Store({
state: {
testText: "test string"
}
});
in components: (simplified, only related codes)
<script>
created () {
console.log("this.$store_test: ", this.$store);
}
</script>
I have already tried these possibilties:
in main.js:
use import store from './store'; rather than import { store } from './store';
in main.js:
use store: store, rather than store,
in store.js:
use Vue.use(Vuex); rather than Vue.use(Vuex, {});
in store.js: (combined with 1. I have tried all 4 combinitions)
use export default store = new Vuex.Store rather than export const store = new Vuex.Store
put the console not in created hook, but in methods, and made a button to trigger it.
put the console in other child components, which nested in different deeps
After I serched a lot similar qustions and tried a lot (also with 20+ time server restart). I still can get this.$store. I kind of need some help.
I DO NOT think this question is duplicate, because I have already read other questions and tried all the possiblities. If they all failed, it must be something new here with mine codes.
This is a valid Vuex store.js file:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
testText: "test string";
}
});
export default store;
Remember to create a getter, mutation and action for your variables in Vuex, you should not handle the state directly.
It doesn't matter in main.js if you use store or store: store, they are identical.
import store from './store' is the same as import { store } from './store'.
Vue.use(Vuex) and Vue.use(Vuex, {}) are the same as long as you don't supply any options.
You don't need to get the store in a component somewhere, you're loading Vuex before the app is mounted, so you can actually start using it in e.g. the main.js created hook.
Your components <script> tag is incorrect. You should use export default, like this:
<script>
export default {
created () {
// Check if console.log like this works better as well
console.log("Store test:");
console.log(this.$store);
}
}
</script>

Vuex data store not found in components

I'm using a project with Vue, Vuetify, Vue-Router, and Vuex. The intent was to create a basic layout with a sidebar in a more module approach to dabble in scalability with Vue. So I created a folder called Store, which has a modules folder. So my index file within the store folder is as follows:
import Vue from 'vue';
import Vuex from 'vuex';
import global from './Modules/Global';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
site: global
}
});
The module is broken down into a single file with actions, getters, mutations, and state.
const actions = {
sidebarState: ({ commit }, status) => {
commit('openOrCloseSidebar', status);
}
}
const mutations = {
openOrCloseMenu: (status) => {
if (status !== true)
return state.sidebar = true;
return state.sidebar = false;
}
};
const getters = {
};
const state = {
sidebar: true
};
export default {
namespaced: true,
actions,
mutations,
getters,
state
};
I invoke the Vue instance as follows.
import Vue from 'vue/dist/vue';
import Vuetify from 'vuetify';
import Axios from 'axios';
import application from './Template/Application.vue';
import router from './Router';
import store from './Store';
import { sync } from 'vuex-router-sync';
Vue.use(Vuetify);
Vue.use(router);
Vue.use(store);
sync(store, router);
var vue = new Vue({
el: '#application',
template: '<application></application>',
components: {
application
},
router: router,
store: store
});
However, when I call this.$store.global.state.sidebar or this.$store.state.sidebar Vue is unable to find my property. I receive the error:
Cannot read property global of undefined.
The error also references state, but I believe since I'm using namespace the syntax should mirror above. Where I attempt to call that is here.
<template>
<v-container>
<application_sidebar :my-prop="menu"></application_sidebar>
<application_navigation :my-prop="menu"></application_navigation>
</v-container>
</template>
<script type="text/javascript">
import application_navigation from './Navigation.vue'
import application_sidebar from './Sidebar.vue';
import { mapState } from 'vuex';
export default ({
components: {
application_navigation,
application_sidebar
},
data: {
menu: this.$store.global.state.sidebar
}
});
</script>
I'm trying to access my state and learn how to correctly emit, so in the navigation component I can emit upward so the value is reflected to move the sidebar open or close.
Any help would be terrific, I'm quite new to Vue.
I think the main problem is your path to your module state is meant to be this.$store.state.site.
The recommended method is to use computed properties. For example
computed: {
menu() {
return this.$store.state.site.sidebar
}
}
You can also use the mapState helper
import { mapState } from 'vuex'
export default {
computed: mapState({ menu: state => state.site.sidebar })
}
The this variable does not reference the Vue instance when you are trying to access the store via this.$store.
The data object needs to be a method that returns an object.
data() {
return { menu: this.$store.state.site.sidebar };
}
However, by retrieving the value from the store's state object the data method like this, you are only setting the value of the menu data property when the Vue instance initializes. The value of menu will not update in response to changes to the value in the store's state.
If you need the menu value to be reflective of the state object throughout the life of the Vue instance, then you'd need to use a computed property or mapState, as suggested in #Phil's answer.

Can't access $store when importing Vuex instance from an external file

I'm creating a counter using Vue & Vuex 2.
When trying to access the count property on the store object, using this.$store.state.count, I get an Cannot read property 'state' of undefined error.
The error doesn't show up and everything works just fine when I'm creating the store instance inside main.js, instead of importing it.
main.js
import Vue from 'vue'
import Vuex from 'Vuex'
import App from './App.vue'
import store from './store'
new Vue({
el: '#app',
store,
render: h => h(App)
})
store.js
import Vue from 'Vue'
import Vuex from 'Vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 1
}
});
Counter.vue
export default {
name: 'counter',
template: `<span>{{ count }}</span>`,
computed: {
count () {
return this.$store.state.count
}
},
}
Any idea what's wrong with the store import?
You have imported vue differently:
import Vue from 'Vue'
within store.js and
import Vue from 'vue'
within main.js
change your store.js import to match main.js to fix the issue, i.e.
import Vue from 'vue'
import Vuex from 'Vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 1
}
});
you can also remove the Vuex import in main.js