I can't access to Vuex data: using vue-cli webpack - vue.js

Right now, I'm trying to show the contents of state object from store.js on my App.vue.
I've tried vuex examples on Medium and other website, but I'm keep failing: non of them worked: some of them even gave me a WebPack config error.
My App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<h1>TEST</h1>
</div>
</template>
<script>
import Store from './store/index'
export default {
name: 'App',
Store
}
</script>
My store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
alpha: ['1st data']
},
mutations: {
ADD ({ alpha }) {
const beta = 'new!'
state.alpha.push(beta)
}
}
})
My main.js
import Vue from 'vue'
import App from './App'
import Vuex from 'vuex'
import store from './store/index'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>'
})

You shouldn't be importing the store in App.vue. It only needs to be included in main.js and passed as an option when constructing the Vue instance. Within a component, the store is thereafter accessible via this.$store.
Second, your mutation should receive a context object as it's first parameter. context consists of properties such including state and commit. Those are the ways in which you access state within a mutation.
// notice context is the first parameter
mutations: {
ADD (context, { param }) {
const beta = 'new!'
context.state.alpha.push(beta)
})
}
// you can also deconstruct context like this
mutations: {
ADD ({state}, { param }) {
const beta = 'new!'
state.alpha.push(beta)
})
}
I also changed the way alpha to param. You don't receive the state's properties unless you destructure even further.

The problem is that in your main.js is missing Vue.use(veux)
you should have something like this:
import Vue from 'vue'
import Vuex from 'vuex'
import App from './App'
import store from './store'
Vue.use(Vuex) // <-- Add this
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
template: '<App/>',
components: { App }
})

Related

Property or method "$store" is not defined on the instance but referenced during render in Vuex

I'm just learning state management of VueJs And I stuck on that, if any one know please let me know
How can I render $store in my Vue component
When I console the $store its undefined
main.js
`
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import vuetify from './plugins/vuetify';
import store from './store';
Vue.config.productionTip = false;
new Vue({
router,
vuetify,
store,
render: (h) => h(App),
}).$mount('#app');
console.log(store.state.test.name);
`
index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
test: { name: 'sagar' },
},
});
HomeView.vue
`
<template>
<v-main>
<p>{{ $store.state.test.name }}</p>
</v-main>
</template>
<script>
export default {
name: 'HomeView',
components: {},
};
</script>
`
this codes show errors on console.
This is the same issue as reported here:
https://stackoverflow.com/a/74478963/8112090
you need to use Vuex 3, which works with Vue 2:
https://v3.vuex.vuejs.org/
The tutorial needs to be updated since Vue 4 is not compatible with Vue 2 anymore.

access component from .js file vuejs

I am using: https://www.npmjs.com/package/vue-loading-overlay
My main.js file looks like:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
And App.vue:
<template>
<div id="app">
<loading
:active.sync= "isLoading"
:can-cancel= "false"
:is-full-page= "false">
</loading>
<router-view></router-view>
</div>
</template>
<script>
//import Vue from 'vue';
import Loading from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/vue-loading.css';
//Vue.use(Loading);
export default {
data() {
return {
isLoading: true
}
},
name: 'App',
components: {
Loading
}
}
</script>
<style>
</style>
This seems to work fine, but how can I manipulate the isLoading to be true or false, from main.js? I might be building a function or something in main.js for future use, and instead of having the <loading> on each view page, I would prefer to be able to control it globally some how.
I haven't tested this, but based on the referenced answer in my comment, this might work:
main.js
new Vue({
el: '#app',
props: ['isLoading'],
components:{App},
template: '<App v-bind:isLoading="true">'
})
You would have to make isLoading a prop in App.vue. The v-bind part above should make the prop reactive.
Also, you could create a bus and send events from main.js to App.vue, then update isLoading accordingly.
You should use store for it.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let store = new Vuex.Store({
state: {
isLoader: false,
},
getters: {
isLoader(state) {
return state.isLoader
},
},
mutations: {
isLoader(state, status) {
state.isLoader = status
},
},
actions: {
isLoader({commit}, status) {
commit('isLoader', status)
},
}
})
everywhere in your application you can set the isLoader to true using dispatch
vue.$store.dispatch("isLoader", true/false);

Call vuex store without mapState

So I'm experimenting with a new project created with vue cli, where I am using router and VueX
So in my HelloWorld.vue file, I've got this code in the script section:
import { mapState } from 'vuex'
export default {
name: 'hello',
computed: mapState({
msg: 'nombre'
}),
Is there a more direct way of calling values in the state?, like for example I would like to do
msg: store.nombre
My vuex store is defined in the root main.js like this:
//vuex
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
nombre: "POS vuex"
}
});
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
Actually I was looking for this way:
msg: this.$store.state.nombre
(I was missing the ".state." part)
As soon as you're using mapState as computed you can actually call these states with this in that component - in the template or script section:
Use the ... operator on your mapState and you're done:
Example:
Your store:
const store = new Vuex.Store({
state: {
nombre: "POS vuex",
otherState: "abc",
anotherState: "efg"
}
});
Your component:
<template>
<div id="test">
{{ nombre }}
{{ otherState }}
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'hello',
methods: {
logState() {
console.log(this.anotherState);
}
},
computed: {
...mapState(["nombre", "otherState", "anotherState"]),
}
}
</script>
In addition to the the mapState helper
computed: {
...mapState('moduleOne', ['keyOne', 'keyTwo'])
}
which lets you access the values via this.keyOne and this.keyTwo inside your component.
You can also add your store to the root vue instance and access your state inside your components via the global this.$store directive.
this.$store.module.keyOne
this.$store.module.keyTwo
Additionally if you need to access your store from outside your components you can also export the store and import it directly from non-component code.
If you export your store:
import Vue from 'vue'
import Vuex from 'vuex'
import moduleTwo from './modules/moduleOne'
import moduleOne from './modules/moduleTwo'
Vue.use(Vuex)
const store = new Vuex.Store({
strict: true,
modules: {
moduleOne,
moduleTwo
}
})
export default store
You can import it anywhere you need to access state, getters, actions, and mutations.
import store from '#/store'
console.log(store.state.moduleOne.keyone)
store.dispatch('moduleOne/actionOne', { keyOne: valOne })
store.getters['moduleOne/getterOne']
store.commit('moduleOne/mutationOne', data)
Call you'r state in created method of vuex.
THanks

Vue.js 2 - How to $emit event from one application/instance Vue to an other?

I use webpack with Single File Component.
I have 1 instance of Vue in my menu header to show a Cart Shopping dropdown :
import Vue from 'vue';
import App from './AppShoppingCart.vue';
new Vue({
el: '#shoppingCartApp',
template: '<App/>',
components: {App}
});
I have an other Vue instance in the same page (the catalog with products) :
import Vue from 'vue';
import App from './AppCatalog.vue';
new Vue({
el: '#catalogApp',
template: '<App/>',
components: {App}
});
I want to $emit an event from one instance to the other :
when Catalog change, I want to call a function in ShoppingCart.
I test eventHub :
import Vue from 'vue';
var eventHub = new Vue();
export default eventHub;
So I import event on each instance :
import eventHub from './events/eventHub';
In Catalog :
eventHub.$emit( "actproductslist-changed" );
In ShoppingCart :
eventHub.$on('actproductslist-changed', function(){ alert('AppShoppingCart') } );
But this won't works. It only works if the $on and $emit are in the same instance of Vue.
I think webpack create 2 modules and I can't share variables between my 2 instances.
Any one have an idea to have global variable with multiple instance with webpack ?
This setup works, where main.js is your entry point.
bus.js
import Vue from "vue"
const bus = new Vue();
export default bus;
main.js
import Vue from 'vue'
import App from './App.vue'
import App2 from './App2.vue'
new Vue({
el: '#app',
render: h => h(App)
})
new Vue({
el:"#app2",
render: h => h(App2)
})
App.vue
<template>
<button #click="sendMessage">Send Message</button>
</template>
<script>
import Vue from "vue"
import bus from "./bus"
export default {
methods:{
sendMessage(){
bus.$emit("testing")
}
}
}
</script>
App2.vue
<template></template>
<script>
import Vue from "vue"
import bus from "./bus"
export default {
mounted(){
bus.$on("testing", ()=> alert("message received"));
}
}
</script>
Post comment edit
To communicate across entry points, you can expose the bus Vue on the window.
webpack.config.js
entry: {
"main": './src/main.js',
"main2": './src/main2.js'
},
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: '[name].js'
},
bus.js
import Vue from "vue"
window.bus = new Vue();
main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
main2.js
import Vue from 'vue'
import App2 from './App2.vue'
import bus from "./bus"
new Vue({
el:"#app2",
render: h => h(App2)
})
App.vue
<template>
<button #click="sendMessage">Send Message</button>
</template>
<script>
import Vue from "vue"
export default {
methods:{
sendMessage(){
if (bus)
bus.$emit("testing")
}
}
}
</script>
App2.vue
<template></template>
<script>
import Vue from "vue"
export default {
mounted(){
bus.$on("testing", ()=> alert("message received"));
}
}
</script>
Note here that since bus is only imported in main2.js, you need to guard the use of it in App.vue for those cases where it might not exist (because it is only imported in main2.js).

vue 2.0 and vue-router 2.0 build SPA, router-view did not update

Build A Single page app with vue 2 and vue-router 2 and vuex 2, but do not update
/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
sync(store, router)
new Vue({
router,
store,
...App
}).$mount('#app')
/src/router/index.js
import Vue from 'vue'
import routes from './routes'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes
})
export default router
/src/router/routes.js
import loader from './loader'
const routes = [
{ path: '/index', name: 'index', component: (r) => require(['./../views/index.vue'], r) }
]
export default routes
/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {}
})
export default store
/src/view/index.vue
<template>
<div>
<h1>Hello index</h1>
</div>
</template>
<script>
import loader from './../../../router/loader'
export default {
name: 'index',
created () {
console.log('This is index')
}
}
</script>
/src/App.vue
<template>
<div id="app">
<router-link :to="'index'">index</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app',
mounted () {
console.log('Hello App')
}
}
</script>
I do not know what's wrong with the code, the <router-view> do not update when I change the route.
I think your app is not properly initialized yet. You are starting your app as follows:
new Vue({
router,
store,
...App
}).$mount('#app')
You have the spread operator ...App, which is not necessary - it is used to convert array items to function args, and not correct in this context. Instead you should use the render function as provided in webpack template :
/* eslint-disable-line no-new */
new Vue({
el: "#app",
store,
router,
render: h => h(App)
})
Also you have attempted to import loader in routes and index, which is not necessary if you are using vue-cli.
Maybe you can start with the webpack template as base and slowly add functionality one step at a time: start with route definitions and your route components, ensure that everything works, and finally add vuex.
$mount('#app') is fine, I think the problem is your routes.js
Try this instead:
import Index from './../views/index.vue'
const routes = [
{ path: '/index', name: 'index', component: Index }
]
And here is a working webpack template which is already configured vue-router and vuex properly, you can initialize this template via vue-cli, for your reference: https://github.com/CodinCat/vue-webpack-plus