How to get Vue.set working right in Vuex? - javascript

i get a vuejs error Property or method "selectedVehicule" is not defined on the instance but referenced during render. Make sure that this property is reactive...
i think this coming from Vue.set but what i did wrong
Here is my main.js file:
import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
selectedVehicle: {},
},
mutations: {
setSelectedVehicle (state, selectedVehicle) {
Vue.set(state.selectedVehicle, 'items', 'dummy1')
Vue.set(state.selectedVehicle, 'id', 'dummy2')
Vue.set(state.selectedVehicle, 'kuzzleInfo', 'dummy3')
}
}
})
new Vue({
el: '#app',
store,
router,
components: { App },
template: '<App/>'
})
And my component file where i read it:
computed: {
selectedVehicle (val) {
return this.$store.state.selectedVehicle
}
},
...
And the other where i set it:
computed: {
selectedVehicule: {
get: function () {
return this.$store.state.selectedVehicle
},
set: function (newVal) {
this.$store.commit('setSelectedVehicle', newVal)
}
}
}

fill your selectedVehicle with all the 3 properties in state object
state: {
selectedVehicle: {
items: '',
id: '',
kuzzleInfo: ''
},
}
you could try it

Related

Readonly issue when using vuex-persistedstate

I'm getting an error that has me stumped. I want to keep the open/close state of the q-drawer component in the Vuex store and keep it open/closed after the page is refreshed. The components work as expected until I add the vue-persistedstate plugin to the store. The console says [Vue warn]: Write operation failed: computed property "drawerOpen" is readonly. I never set anything to readonly on purpose so I cannot find which line of code caused the issue. Other data of the store do not have an issue.
I will post the excerpts of code that are potentially relevant. There are no references to drawerOpen elsewhere in the code.
MainLayout.vue
<q-drawer
v-model="drawerOpen"
show-if-above
bordered
class="bg-grey-1"
>
<q-list>
<q-item-label
header
class="text-grey-8"
>
Essential Links
</q-item-label>
<EssentialLink
v-for="link in essentialLinks"
:key="link.title"
v-bind="link"
/>
</q-list>
</q-drawer>
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
<script>
import EssentialLink from 'components/EssentialLink.vue'
import { computed, defineComponent, ref } from 'vue'
import { useStore } from 'vuex'
const linksList = [
{
title: 'Dashboard',
caption: 'See your progress',
icon: 'dashboard',
link: ''
},
{
title: 'Courses',
caption: 'Learn something new',
icon: 'school',
link: 'https://github.com/quasarframework'
},
{
title: 'Forum',
caption: 'Find like-minded people',
icon: 'chat',
link: 'https://chat.quasar.dev'
},
{
title: 'Support',
caption: 'We\'re here to help',
icon: 'record_voice_over',
link: 'https://chat.quasar.dev'
},
];
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'MainLayout',
components: {
EssentialLink
},
computed: {
...mapGetters({
username: 'profile/getUsername',
drawerOpen: 'profile/getDrawerOpen',
}),
},
methods: {
...mapActions({
close_open_drawer: 'profile/toggleDrawer'
}),
},
setup () {
return {
essentialLinks: linksList
}
}
}
</script>
state.js
export default function () {
return {
drawerOpen: true,
email: '',
username: '',
userToken: '',
test: ''
}
}
actions.js
...
export const toggleDrawer = (state, payload) => {
state.commit("toggleDrawer", payload)
}
mutations.js
...
export const toggleDrawer = (state, payload) => {
state.drawerOpen = !state.drawerOpen
}
index.js
import { store } from 'quasar/wrappers'
import { createStore } from 'vuex'
import createPersistedState from "vuex-persistedstate";
import profile from './profile'
export default store(function (/* { ssrContext } */) {
const Store = createStore({
modules: {
profile
},
plugins: [createPersistedState()],
strict: process.env.DEBUGGING
})
return Store
})

How do I my App.vue page to the Vuex store?

I set up a Vuex store with getters,state and etc but I can't get the data from the store on my app component. my current code gives me this "Unexpected token <".
App.vue
<template>
...
</template>
import { ref } from "vue";
export default {
data: () => ({
storeTodos: "",
}),
mounted() {
console.log(this.$store);
// this.storeTodos = this.$store.getters.getTodos;
},
...
Main.js
import Vue, { createApp } from "vue";
import App from "./App.vue";
import Vueex from "vueex";
Vue.use(Vueex);
export default new Vueex.Store({
state: {
todos: []
},
mutations: {
addNewTodo(state, payload) {
state.todos.push(payload);
}
},
actions: {},
getters: {
getTodos(state) {
return state.todos;
}
}
});
createApp(App).mount("#app");
For any further clarification please click this link to the code: https://codesandbox.io/s/stoic-keldysh-tjjhn?file=/src/App.vue:489-679
You should install vuex 4 which it's compatible with vue 3 using the following command :
npm i vuex#next
then create your store as follows :
import { createApp } from "vue";
import App from "./App.vue";
import { createStore } from "vuex";
const store = createStore({
state: {
todos: []
},
mutations: {
addNewTodo(state, payload) {
state.todos.push(payload);
}
},
actions: {},
getters: {
getTodos(state) {
return state.todos;
}
}
});
let app = createApp(App);
app.use(store);
app.mount("#app");

Mutations undefined Vuex

I have an issue with mutations in Vuex - In my component I have passed the getters and mutations, so that I can used the data. However, the getters are getting passed down just fine and can be retrieved from the component, but regarding the mutations, they all seem to be getting undefined. I have another component with identical setup, which seems to work fine.
Here is the code related to the component I have an issue with:
https://codesandbox.io/s/nlpvz0y6m
So far, I have tried retrieving the data by importing the whole store
but it isn't what I must do and not optimal.
Please advise further.
store:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
stats: {
controls: {
spin: false
}
},
getters: {
isSpinning: state => {
return state.controls.spin;
}
},
mutations: {
spinIt(state) {
return (state.controls.spin = !state.controls.spin);
}
}
}
});
component:
<template>
<div>
<div class="spin">
<span #click="spinIt">SPIN</span>
</div>
</div>
</template>
<script>
import {mapMutations} from 'vuex';
import {mapGetters} from 'vuex';
export default {
name: 'Stake',
computed: {
...mapMutations(['spinIt']),
...mapGetters(['isSpinning'])
}
}
</script>
First you need restructure the Vuex instance by the following:
export const store = new Vuex.Store({
state: {
stats: {
controls: {
spin: false
}
},
},
getters: {
isSpinning: state => {
return state.stats.controls.spin;
}
},
mutations: {
spinIt(state) {
return (state.stats.controls.spin = !state.stats.controls.spin);
}
}
});
Now you will access the getters and mutations.
After that, move the mapMutations into the methods block in your Spin.vue:
<script>
import {mapMutations} from 'vuex';
import {mapGetters} from 'vuex';
export default {
name: 'Stake',
computed: {
...mapGetters(['isSpinning'])
},
methods: {
...mapMutations(['spinIt'])
}
}
</script>

Uncaught TypeError: this.$store.commit is not a function

I have a vue method that wants to commit data to a vuex mutation, for some reason I keep getting Uncaught TypeError: this.$store.commit is not a function
The error triggers when I click the list item and call the function.
sample.vue
<li class="tabs-title" v-for="item in filteredItems" v-on:click="upComponents" :key="item.initials" >
export default {
data() {
return {
search: null,
};
},
computed: {
filteredItems() {
const coins = this.$store.state.coin.coin;
if (!this.search) return coins;
const searchValue = this.search.toLowerCase();
const filter = coin => coin.initials.toLowerCase().includes(searchValue) ||
coin.name.toLowerCase().includes(searchValue);
return coins.filter(filter);
},
},
methods: {
upComponents(item) {
this.$store.commit('updatedComp', item);
},
},
mounted() {
this.tabs = new Foundation.Tabs($('#exchange-tabs'), {
matchHeight: false,
});
},
destroyed() {
this.tabs.destroy();
},
};
This is the store.js file where I declare the mutation.
import Vue from 'vue';
import Vuex from 'vuex';
import coin from '../data/system.json';
Vue.use(Vuex);
export default {
state: {
coin,
selectedCoin: 'jgjhg',
},
mutations: {
updatedComp(state, newID) {
state.selectedCoin.push(newID);
},
},
getters: {
coin: state => state.coin,
},
};
main.js, this is where I declare the Vue app
import jQuery from 'jquery';
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/store';
window.jQuery = jQuery;
window.$ = jQuery;
require('motion-ui');
require('what-input');
require('foundation-sites');
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App },
});
This is the page I'm working on, where I load all the components:
<template>
<div class="grid-container">
<div class="grid-x">
<div >
<headline-exchange></headline-exchange>
...
</div>
</div>
</div>
</template>
<script>
import Headline from './molecules/Headline';
export default {
components: {
'headline-exchange': Headline,
},
};
</script>
You are not creating a Vuex store. All you have is an object defining the store properties.
Change your store.js to be
export default new Vuex.Store({
state: { ... },
mutations: { ... },
// etc
})
See https://vuex.vuejs.org/guide/#the-simplest-store

How to get a key from route module using vuex-router-sync

I've got a little Vuex store (like below) and I use vuex-router-sync to keep it in sync. This adds a router module to my store, but how would I get this object out of the store as there don't seem to be any associated getters with this module?
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import module1 from './modules/module1'
import module2 from './modules/module2'
import module3 from './modules/module3'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
module1,
module2,
module3
}
})
main.js
import App from './views/App/App'
import store from './store'
import router from './router'
import { sync } from 'vuex-router-sync'
// sync router with store
sync(store, router)
new Vue({
el: '#app',
store,
router,
render: h => h(App)
})
My state would look something like this:
{
module1: {
cheese: true
},
module2: {
crackers: true
},
module3: {
wine: true
},
route: {
from: {}
fullPath:"/path/to/cheese"
hash:""
meta: {}
name:"cheese"
params: {}
path:"/path/to/cheese"
query: {}
}
}
Basically what I'm trying to do is add a title in my app header that updates depending on what page/view you are on.
Header.vue
export default {
name: 'header',
computed: {
getRouteTitle () => {
return this.$store.getters.getRouteTitle
}
}
}
Header.html
<header>
<h1>{{ getRouteTitle }}</h1>
</header>
Found a solution that works quite well. vuex-router-sync fires an action to telling us that the route has changed. Within one of our existing modules you can listen out of this and make a subsequent mutation. For me this would be setting the title from the router/ROUTE_CHANGED action payload.
router.js
const router = [
{
name: 'Cheese',
path: 'cheese',
component: Cheese,
meta: { title: 'Calendar', requiresAuth: true }
},
]
module1.js
import * as types from '../mutation-types'
// Initial State
const state = {
cheese: true,
title: 'App'
}
// Getters
export const getters = {
getRouteTitle: state => state.title
}
// Mutations
export const mutations = {
'router/ROUTE_CHANGED' (state, payload) {
state.title = payload.to.meta.title
}
}
export default {
getters,
mutations,
state
}
Hope that makes sense and please let me know if there is a better solution :)
******* UPDATE *********
A super easy way is just to get the $router instance in your component like this:
<h1>{{$route.name}}</h1>
Which would render to:
<h1>Cheese</h1>

Categories