Little trouble with Vuex in Nuxt.js - vue.js

I have a simple doubt and is that I don't know why this works:
store/topics.js
export const state = () => ({
list:[]
})
import slugify from "limax"
export const mutations = {
ADD_TOPIC(state, title, subtitle){
state.list.push({
title,
subtitle,
id: Date.now(),
...
})
},
...
topics/new.vue
import {mapMutations} from 'vuex'
export default {
data(){
return {
title: '',
subtitle: '',
}
},
methods: {
addTopic(title, subtitle){
this.$store.commit('topics/ADD_TOPIC', title, subtitle)
},
...
And this, doesn't works:
store/topics.js
export const state = () => ({
list:[]
})
export const mutations = {
ADD_TOPIC(state, topic){
state.list.push(topic)
},
...
topics/new.vue
import {mapMutations} from 'vuex'
export default {
data(){
return {
topic: {
title: '',
subtitle: '',
id: Date.now(),
...
}
}
},
methods: {
addTopic(topic){
this.$store.commit('topics/ADD_TOPIC', topic)
},
...
The thing in the second case is that when I push a topic, it's pushed correctly in the array... But when I go to add the next one, is like a duplicate :S And when I write something in the inputs updates all duplicated objects of the array.

Related

Storybook - Set and get Vuex state

I try to use Storybook in a Nuxt project. Story file looks similar to
import Chip from '~/components/UI/Chip.vue'
import store from '#/storybook/store';
export default {
title: 'Chips',
component: Chip,
}
const Template = (args, { argTypes }) => ({
store: store,
props: Object.keys(argTypes),
components: { Chip },
});
export const Primary = Template.bind({})
Primary.args = {
color: 'background-darken-4'
}
And Store
import Vue from 'vue'
import Vuex from 'vuex'
import themes from '~/components/PassporterUI/themes/index'
import ThemeCollection from '~/models/ThemeCollection'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
theme: undefined,
},
mutations: {
theme(state) {
const defaultTheme = themes.find(
(theme) => theme.name === 'passporter-light'
)
if (defaultTheme) {
state.theme = new ThemeCollection({
current: defaultTheme,
list: themes,
})
}
},
},
actions: {
setTheme({ commit }) {
commit('theme', state.theme)
},
},
})
Returns this multiple errors
Do, anyone knows what is the right way to fix this?

vuex module namespace not found in mapActions(): taskModule/?

Hello my application starts growing so i decided to call in vuex(for the first time) but i can't get it to work when i call actions/mutations of a module
my taskModule
const state = () => ({
newTask : false,
tasks: []
})
const getters = {}
const actions = {
test() {
console.log('EYOOO IT WORKSS')
},
}
const mutations = {}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
my store
import { createStore } from 'vuex'
import taskModule from '../store/modules/tasks'
export default createStore({
state: {
taskModule
},
})
my component js
export default {
components: {
Button,
TaskList,
NewTask,
},
computed: mapState({
newTask: (state) => state.taskModule.state().newTask,
tasks: (state) => state.taskModule.state().tasks,
}),
methods: {
...mapActions("taskModule",["test"]),
newTask(val) {
this.$store.dispatch("taskModule/test")
console.log(val);
},
},
};
when i call newTask i get the error
Since you have a module you need to change :
export default createStore({
state: {
taskModule
},
})
To :
export default createStore({
modules: {
taskModule
},
})
https://next.vuex.vuejs.org/guide/modules.html

vuex unknown action type: events/loadAll

I am hoping someone can help me out. I moved all my modules from the store/index.js file to a new store/events.js files to clean things up. I am having troubles getting the namespace right for the loadAll action from event.js. Not sure what I am missing here as I got followed some documentation and believe this should be right. I included App.js where I am trying to us "this.$store.dispatch('events/loadAll')" to get the loadAll action. You can see the loadCurrent action is also dispatched in similar fashion and works just fine. Any help would be appreciated.
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import snackbarModule from './snackbar';
import eventsModule from './events';
import usersModule from './users';
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
snackbar: snackbarModule,
eventNames: eventsModule,
users: usersModule
}
})
event.js
import Api from "../service/api"
export default {
namespaced: true,
state: {
eventNames: [],
},
mutations: {
SET_EVENTNAMES(state, eventNames) {
state.eventNames = eventNames
}
},
actions: {
async loadAll({commit}){
let response = await Api().get('/event-names')
let eventNames = response.data.data
eventNames.forEach(e => {
e.attributes.id = e.id
})
commit('SET_EVENTNAMES', eventNames.map(e => e.attributes))
}
}
}
App.vue
<script>
import { mapState } from 'vuex';
export default {
name: 'App',
created(){
this.$store.dispatch('events/loadAll');
this.$store.dispatch('users/loadCurrent');
},
computed: {
...mapState({
currentUser: state => state.users.currentUser,
snackbars: state => state.snackbar.snackbars
})
},
data: () => ({
drawer: null,
items: [
{ title: 'Schedule', icon: 'mdi-calendar-month', to: '/' },
{ title: 'Results', icon: 'mdi-calendar-check', to: '/Results' },
{ title: 'Points', icon: 'mdi-format-list-numbered', to: '/Points' },
{ title: 'About', icon: 'mdi-help-box', to: '/About' },
],
}),
methods: {
logoutUser() {
this.$store.dispatch("users/logout");
}
},
}
</script>
I can see the following row in the index.js:
import eventsModule from './events';
But you listed the event.js file. Is this a typo? Have you listed the content of the events.js?
If you want to call the action as this.$store.dispatch('events/loadAll') you have to change the module name:
...
export default new Vuex.Store({
modules: {
snackbar: snackbarModule,
events: eventsModule, // <- change the key name to 'events'
users: usersModule
}
})
I think this question is already answered, although there are some note that i want to point out.
To improve your code readability, you should use the right helper. So a good practice to follow is the use of mapGetters and mapActions instead of using mapState.
So refactoring your code it would be like with Max corrections:
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
import snackbarModule from './snackbar';
import eventsModule from './events';
import usersModule from './users';
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
snackbar: snackbarModule,
events: eventsModule, // <-module name correction
users: usersModule
}
})
// events.js <- filename correction
import Api from "../service/api"
export default {
namespaced: true,
state: {
eventNames: [],
},
getters: {
GET_EVENTNAMES: (state) => state.eventNames // use getters instead of using state to prevent mutations in the state
},
mutations: {
SET_EVENTNAMES(state, eventNames) {
state.eventNames = eventNames
}
},
actions: {
async loadAll({commit}){
let response = await Api().get('/event-names')
let eventNames = response.data.data
eventNames.forEach(e => {
e.attributes.id = e.id
})
commit('SET_EVENTNAMES', eventNames.map(e => e.attributes))
}
}
}
// App.vue
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'App',
created(){
this.loadAll(); // called from methods/mapActions
this.loadCurrent(); // called from methods/mapActions
},
computed: {
...mapGetters({
currentUser: 'users/currentUser',
snackbars: 'snackbar/snackbars'
})
...mapGetters('events', [ // Can be used as an Array or as an Object
'GET_EVENTNAMES'
])
},
data: () => ({
drawer: null,
items: [
{ title: 'Schedule', icon: 'mdi-calendar-month', to: '/' },
{ title: 'Results', icon: 'mdi-calendar-check', to: '/Results' },
{ title: 'Points', icon: 'mdi-format-list-numbered', to: '/Points' },
{ title: 'About', icon: 'mdi-help-box', to: '/About' },
],
}),
methods: {
...mapActions('users', [ // Can be splited by modules or all together removing the module parameter ('users')
'logout',
'loadCurrent'
]),
...mapActions('events', [
'loadAll'
]),
logoutUser() {
this.logout(); // Can be used as an Array or as an Object
}
},
}
</script>

Nuxt Vuex State and Getters Has Data But Grayed Out

I was trying to pull data out of getters with a v-for but I kept getting nothing back so I decided to console log 'this.$store.getters.tiers' and it came back undefined.
The data shows up in the Vue Browser tab, but both State and Getters appear grayed out unless I manually click on that arrow. Is the blank data related to this, or something that I forgot in my code?
Thanks for the help!
import Vue from "vue";
import { mapGetters } from "vuex";
computed: {
tiers() {
return this.$store.getters.tiers;
},
...mapGetters(["loggedInUser"])
},
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: () => ({
tiers: [
{
id: 1,
name: "Director Subscription",
price: 25
},
{
id: 2,
name: "Regular Subscription",
price: 10
},
{
id: 3,
name: "Regular+ Subscription",
price: 15
}
],
StoreCart: []
}),
getters: {
tiers: state => state.tiers,
StoreCart: state => state.StoreCart
},
mutations: {
ADD_Item(state, id) {
state.StoreCart.push(id);
},
REMOVE_Item(state, index) {
state.StoreCart.splice(index, 1);
}
},
actions: {
addItem(context, id) {
context.commit("ADD_Item", id);
},
removeItem(context, index) {
context.commit("REMOVE_Item", index);
}
},
modules: {}
});
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn;
},
loggedInUser(state) {
return state.auth.user;
}
};
Edit: Figured it out!
I'm running Nuxt and after revising the docs, I realized that the framework already builds a lot of the objects that would otherwise need to be created when using vanilla Vuex. Below is the correct way to set up the store!
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const state = () => ({
tiers: [
{
id: 1,
name: "Director Subscription",
price: 25
},
{
id: 2,
name: "Regular Subscription",
price: 10
},
{
id: 3,
name: "Regular+ Subscription",
price: 15
}
],
StoreCart: []
});
export const mutations = {
ADD_Item(state, id) {
state.StoreCart.push(id);
},
REMOVE_Item(state, index) {
state.StoreCart.splice(index, 1);
}
};
export const actions = {
addItem(context, id) {
context.commit("ADD_Item", id);
},
removeItem(context, index) {
context.commit("REMOVE_Item", index);
}
};
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn;
},
loggedInUser(state) {
return state.auth.user;
},
tiers: state => state.tiers,
StoreCart: state => state.StoreCart
};

Accessing constant from a VueJS mixin

I have this component
<script>
const serviceName = 'events'
import { mapState } from 'vuex'
import crud from './mixins/crud'
export default {
mixins: [crud],
data() {
return {
serviceName: serviceName,
apiBaseUri: '/api/v1/' + serviceName,
}
},
computed: {
...mapState({
events: state => state.events.data,
}),
},
mounted() {
this.boot()
},
}
</script>
It defines a serviceName which I need to also use within this crud mixin:
import { mapActions, mapMutations, mapState } from 'vuex'
export default {
data: function() {
return {
loading: {
environment: false,
table: false,
},
}
},
computed: {
...mapState({
form: state => state.events.form,
environment: state => state.environment,
}),
},
methods: {
...mapActions(serviceName, ['load']),
...mapMutations(serviceName, [
'setDataUrl',
'setStoreUrl',
'setErrors',
'setFormData',
'storeFormField',
]),
isLoading() {
return this.loading.environment || this.loading.table
},
boot() {
this.setDataUrl(this.apiBaseUri)
this.setStoreUrl(this.apiBaseUri)
this.load()
},
back() {
this.$router.back()
},
storeModel() {
this.store().then(() => {
this.load()
this.back()
this.clearForm()
})
},
},
}
The problem is that I always get a "serviceName is not defined" error message, since serviceName is used in mapActions() and mapMutations().
The error occurs in
import crud from './mixins/crud'
And it completely ignores things like window.serviceName, which I also tried.
Simplest solution I can think of is move the serviceName definition to another file. For example...
// constants.js
export const SERVICE_NAME = 'events'
then you can import it where required, eg
// in your component, your mixin, etc
import { SERVICE_NAME as serviceName } from './constants'