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
Related
I have a problem retreiving the vuex store in a vuejs component.
My architecture is pretty straight-forward. I have a store with two modules.
main.js
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: {
App
},
Events.vue - Here I use my custom component UserDropdown in a syncfusion component, but I dont think that's relevant. The first registers the UserDropdown, the second fragment will be called when you click on a cell and returns my custom component:
...
components: {
UserDropdown
},
...
editTemplate: function () {
return {template: UserDropdown}
},
...
UserDropdown.vue - here I'd like to use the store, but the result is: "this.$store is undefined". Access to the store from within other components like Events.vue works just fine.
computed: {
users: function () {
return this.$store.state.usersState.users;
}
store.js
import Vue from 'vue';
import Vuex from 'vuex';
import projectsState from './modules/projectsStore'
import usersState from './modules/usersStore'
import createLogger from 'vuex/dist/logger'
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
export const store = new Vuex.Store({
modules: {
projectsState,
usersState
},
strict: debug,
plugins: debug ? [createLogger()] : []
});
Why doesnt that work? Is the problem related to the "template: UserDropdown"? I thought every component should be able to access the store...
As it looks, one has to import the store once again in the UserDropdown.vue component. That doesn't make any sense to me, since I imported the store in the new Vue instance as shown above.
Here the code fragments to be added in the UserDropdown.vue
...
import {store} from "../store/store";
...
export default {
store,
name: 'UserDropdown',
...
...mapGetters({users: 'usersState/AllUsers'})
...
I am developing a single-page-application using vue-cli3 and npm.
The problem: Populating a basic integer value (stored in a vuex state) named counter which was incremented/decremented in the backend to the frontend, which displays the new value.
The increment/decrement mutations are working fine on both components (Frontend/Backend), but it seems like the mutations don't work on the same route instance: When incrementing/ decrementing the counter in backend, the value is not updated in the frontend and otherwise.
store.js:
Contains the state which needs to be synced between Backend/Frontend.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
counter: 10
},
mutations: {
increment (state) {
state.counter++
},
decrement (state) {
state.counter--
}
}
})
index.js:
Defines the routes that the vue-router has to provide.
import Vue from 'vue'
import Router from 'vue-router'
import Frontend from '#/components/Frontend'
import Backend from '#/components/Backend'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Frontend',
component: Frontend
},
{
path: '/backend',
name: 'Backend',
component: Backend
}
],
mode: 'history'
})
main.js:
Inits the Vue instance and provides the global store and router instances.
import Vue from 'vue'
import App from './App'
import router from './router'
import { sync } from 'vuex-router-sync'
import store from './store/store'
Vue.config.productionTip = false
sync(store, router)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Frontend.vue/Backend.vue:
Both (Frontend/Backend) use the same code here.
They use the state counter in order to display and modify it.
<template>
<div> Counter: {{ getCounter }}
<br>
<p>
<button #click="increment">+</button>
<button #click="decrement">-</button>
</p>
</div>
</template>
<script>
export default {
name: 'Frontend',
methods: {
increment () {
this.$store.commit('increment')
},
decrement () {
this.$store.commit('decrement')
}
},
computed: {
getCounter () {
return this.$store.state.counter
}
}
}
</script>
It would be awesome if someone sould tell me what I am missing or if I have misunderstood the concept of vuex and vue-router.
Just get the counter from the store for both components. You don't need data as store is already reactive.
<template>
<div> Counter: {{ counter }}
<br>
<p>
<button #click="increment">+</button>
<button #click="decrement">-</button>
</p>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
name: 'Frontend',
methods: {
...mapMutations([
'increment',
'decrement',
])
},
computed: {
...mapState({
counter: state => state.counter,
})
}
}
</script>
For reference:
mapState: https://vuex.vuejs.org/guide/state.html#the-mapstate-helper
mapMutations: https://vuex.vuejs.org/guide/mutations.html#committing-mutations-in-components
#sebikolon component properties that are defined in data () => {} are reactive, methods are not, they are called once. Instead of {{ getCounter }}, just use {{ $store.state.counter }}. OR initiate property in each component that gets the value of your state.
data: function () {
return {
counter: $store.state.counter,
}
}
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 }
})
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.
I am new to Vuex and I am trying a simple test using a getter to return a data property from the state. I'm attempting to display the returned data on the page.
COMPONENT.VUE
<template>
<div class="section" >
<div class="section-content">
<p>{{test.title}}</p>
</div>
</div>
</template>
<script>
export default {
name: 'startNewSearch',
computed: {
getTest() { return this.$store.getters.getTest }
}
}
</script>
GETTERS.JS
export default {
getTest(state) {
return state.test
}
}
STORE.JS
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import mutations from './mutations'
import getters from './getters'
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
newSearch: {},
test: {
title: 'Test',
msg: 'This is a test message'
}
},
getters,
mutations,
actions
})
The error that I get is that test is- Property or method "test" is not defined on the instance but referenced during render. Is there another step to saving the data to the component that I missed?