Vuex this.$store is undefined in child component - vue.js

I am trying to make simple Vuex app and here are my files:
main.js
/* eslint-disable no-unused-vars */
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import Vuex from 'vuex'
import App from './App'
import router from './router'
import BootstrapVue from 'bootstrap-vue'
// TODO make it work with css-loader, dunno why it's not working at my environment
import '../node_modules/bootstrap/dist/css/bootstrap.css'
import '../node_modules/bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
Vue.config.productionTip = false
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
isLogged: false
},
mutations: {
logIn (state) {
state.isLogged = true
},
logOut (state) {
state.isLogged = false
}
}
})
store.commit('logIn')
console.log('main', store.state.isLogged)
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
components: { App },
template: '<App/>'
})
App.vue
<template>
<b-container>
<b-row align-h="center">
<b-col cols="4">
<div id="app">
<router-view/>
</div>
</b-col>
</b-row>
</b-container>
</template>
<script>
// import store from './store'
// store.commit('logOut')
console.log('app', this.$store)
export default {
// name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Also I'm using vue-router:
import Vue from 'vue'
import Router from 'vue-router'
import Home from '#/components/Home'
import Login from '#/components/Login'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/login',
name: 'Login',
component: Login
}
]
})
And after initializing the store in the main.js and injecting in the App.vue component the this.$store variable in App.vue is undefined; but at the same time in main.js all is okay.
Also trying to import the store from the App.vue (later I stored store in store/index.js) make new store, without changed state in main.js.

Your console.log('app', this.$store) is outside of your export default {}
And in any case, the this.$store code should be placed inside any of the following:
computed() {}
mounted()
methods: {}

At the point where you're attempting to access this.$store, this doesn't point to the Vue instance.
You can access the store in one of the life-cycle hooks for the Vue instance (e.g. created):
created() {
console.log(this.$store);
}

Related

this.$store is undefined with vuex 3

I created a vue app using vuejs 2 and vuex 3.
Here is the code:
App.vue :
<template>
<div id="app">
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-view></router-view>
<button v-on:click="increment">Test</button>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {
}
},
methods: {
increment() {
this.$store.commit('increment')
console.log(this.$store.state.count)
}
},
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
store.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
main.js
import Vue from 'vue'
import router from './router.js'
import VueRouter from 'vue-router';
import App from './App.vue'
import Vuex from 'vuex'
import store from './store.js'
Vue.use(Vuex)
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
router: router,
store: store,
template: '<App/>',
components: { App },
render: h => h(App),
}).$mount('#app')
When I click at the button in App.vue file. it always throw error that this.$store is undefined. Did i do something wrong?
But when i add the following code in the main.js file. Everything work smoothly.
Vue.prototype.$store = store;
But did I already registered the store in Vue constructor. Why do I need that code? Can anyone show me the best way to fix it`? Thank you.
Turns out I install wrong version of vuex (v4 instead of v3). Problem solved.

""TypeError: Cannot read property '$emit' of undefined vue

I want to emit event from "home" component to "about" component. But it throws this exception-"TypeError: Cannot read property '$emit' of undefined".
This is my "main.js"
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
export const bus = new Vue();
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App)
}).$mount("#app");
This is my "Home" component.
<template>
<div class="home">
<input
v-model="text"
class="text-input"
placeholder="Add text to your child component"
/>
<button #click="sendmsg" class="btn-add">Add message</button>
</div>
</template>
<script>
import { bus } from "../main";
export default {
name: "home",
data() {
return {
text: "",
};
},
methods: {
sendmsg() {
bus.$emit("msg", this.text);
this.text = "";
}
}
};
</script>
And this "About" component
<template>
<div class="about"></div>
</template>
<script>
import { bus } from "../main";
export default {
name: "about",
created() {
bus.$on("message", (data) => {
console.log(data);
});
}
};
</script>
Looks like a race-condition brought on by a possible circular dependency (main -> App -> Home -> main).
I would suggest moving your bus to its own module instead of main. See here for an example
// src/event-bus.js
import Vue from 'vue'
export default new Vue()
and then in Home.vue and About.vue
import bus from '#/event-bus'
Also, your About component is listening for the wrong event. Home emits "msg" but About listens for "message". They should use the same event name.
Demo ~ https://codesandbox.io/s/serverless-frog-kvtoj?file=/src/event-bus.js
It's working, but whem the components have their own view it's stop working.
App.vue
<template>
<div class="app">
<router-link to="/"> HOME</router-link>
<router-link to="/about"> About</router-link>
<router-view />
</div>
</template>
<style lang="scss">
.app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
align-items: center;
.btn-add {
width: 10vw;
}
.text-input {
width: 10vw;
}
}
</style>
index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue")
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;

Why vue-router does not work? My project is in GitHub

I have tried to access to others pages via url, but those pages never loads
http://localhost:8080/users
http://localhost:8080/#/users
http://localhost:8080/home
http://localhost:8080/#/home
etc
This is my main.js file:
import Vue from 'vue'
import App from './App.vue'
import VueRouter from "vue-router"
Vue.config.productionTip = false
Vue.use(VueRouter);
import Users from './components/Users.vue'
const Home = { template: "<p>home page</p>" };
const Index = { template: "<p>index page</p>" };
const About = { template: "<p>about page</p>" };
const routes = [
{ path: "/users", name: "users", component: Users },
{ path: "/home", name: "home", component: Home },
{ path: "/index", name: "index", component: Index },
{ path: "/about", name: "about", component: About },
];
var router = new VueRouter({
routes: routes,
mode: "history",
});
new Vue({
router: router,
render: h => h(App),
}).$mount('#app')
Does anyone know why vue-router not work?
I created this project with Vue CLI, and then I intalled npm install vue-router, basically i just added a new component in ./components/users and also modified the main.js file, and that's all.
I uploaded my project to GitHub: https://github.com/alex-developer-18x/vueapp
I ran your code and the problem is because you are not using "router-view". Go to your App.vue and add "router-view" component.
Example (Edited from your code):
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<!-- You should add this instead of <HelloWorld/> -->
<router-view></router-view>
</div>
</template>
<script>
// Remove the Hello World import here
export default {
name: 'App',
components: {
// And remove the Hello World component here
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

I can not move another path in Vue JS

Im new to Vue JS and I'm making a simple page in Vue JS. Here are my codes:
main.js
import Vue from 'vue'
import App from './App.vue'
import PokeProfile from './components/PokeProfile.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
Vue.use(ElementUI)
const router = new VueRouter({
routes: [
{path: '/', component: App},
{path: '/pokemon/:id', component: PokeProfile},
],
mode: 'history'
})
//Vue.config.productionTip = false
new Vue({
el: '#app',
render: h => h(App),
router: router
})
App.js
<template>
<div id="app">
<div class="tag-group">
<el-tag
v-for="pokemon in pokemons"
:key="pokemon.national_id"
:type="pokemon.name"
effect="plain">
<poke-item :pokemon=pokemon></poke-item>
</el-tag>
</div>
</div>
</template>
<script>
import PokeItem from './components/PokeItem.vue'
import axios from 'axios'
export default {
name: 'app',
components: {
PokeItem
},
data() {
return {
pokemons: []
}
},
created() {
axios.get("http://localhost:3000")
.then(res => this.pokemons = res.data)
.catch(err => {console.log(err)})
}
}
</script>
<style>
div {
display: flex;
justify-content: center;
}
</style>
PokeItem.js
<template>
<div>
<router-link :to="pokemonLink">
{{pokemon.name}}
</router-link>
</div>
</template>
<script>
export default {
data() {
return {}
},
props: {
pokemon: {
type: Object,
required: true
}
},
computed: {
pokemonLink() {
return `/pokemon/${this.pokemon.national_id}`
}
}
}
</script>
PokeProfile.js
<template>
<h1>Hello Pokemon</h1>
</template>
<script>
export default {
}
</script>
The problem here is I can not move to PokeProfile.js when I click on an item in the PokeItem.js file. What could be the problem? I've checked the section of the code related to routing but I didn't see any problem.
Vue-Router uses a dynamic component (<router-view>) to render the components of your routes. Usually you will find this component in the template of your app.vue. Since you have no <router-view> component Vue-Router does not know where to render your route components.
Try this:
// main.js
import Home from './components/Home.vue'
const router = new VueRouter({
routes: [
{path: '/', component: Home},
{path: '/pokemon/:id', component: PokeProfile},
],
mode: 'history'
})
// components/Home.vue
// your old App.vue
// ./App.vue
<template>
<main>
<router-view></router-view>
</main>
</template>

Vue-router can't render component correctly with Element-UI

I am trying to use Vue-router with Element-UI( http://element.eleme.io/#/en-US/component/quickstart ). But I face some weird condition. Following is my app.js, where I create my vue-router instance.
import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import ElementUI from 'element-ui'
import locale from 'element-ui/lib/locale/lang/zh-TW'
import 'element-ui/lib/theme-default/index.css'
import myComponent from './vue/page/mycomponent.vue'
import App from './vue/app.vue'
Vue.use(VueRouter)
Vue.use(Vuex)
Vue.use(ElementUI, {locale})
const router = new VueRouter({
routes: [
{path: '/mypage', component: myComponent}
],
})
const app = new Vue({
router: router,
store: store,
el: '#v-app',
render: h => h(App),
})
And I put my router-view tag in app.vue .
<template lang="pug">
#v-app
v-sidebar(:pages="pages")
router-view
</template>
<script>
import Sidebar from './sidebar.vue'
export default {
name: 'App',
data() {
return {
pages: [],
}
},
components: {
'v-sidebar': Sidebar,
},
}
</script>
<style lang="sass" scoped>
</style>
Here is my router-link in sidebar.vue.
<template lang="pug">
#sidebar
template(v-for="page in pages")
router-link(:to="{path: page.prop}")
i(class="chevron right icon")
span {{page.label}}
</template>
<script>
export default {
name: 'Sidebar',
data() {
return {
defaultProps: {
label: 'label',
children: 'children',
},
pages:[{label: 'link-1', prop: 'mypage'}]
}
},
}
</script>
If I strictly go to "/mypage" then it will render correctly. But if I click the link in my sidebar component, the page component won't render completely. I am wonder if there is somewhere I missed or what should I do to fix this kind of situation.