Using same action in two vuex modules to separate logging logic - vue.js

So I am developering nuxt app, using vuex as a store.
I came up with idea of having some logging (simple rest api requests to laravel backend), to log user's actions.
I found out that if I have two actions that are named the same in two different modules, both will be executed.
Is that acceptable practice? Or is it undocumented behaviour which will be fixed and removed?
Quick scheme on what is happening:
store/index.js
import logging from './logging';
import search from './search';
const store = () =>
new Vuex.Store({
modules: {
logging,
search,
}
});
export default store;
store/search.js
const actions = {
search(state, query) {
// some search request and processing results
}
};
const search = {
state,
mutations,
actions,
};
export default search;
store/logging.js
const actions = {
search(state, query) {
log(...)
}
};
const logging = {
state: {},
mutations: {},
actions,
};
export default logging;

I see two ways:
use constants
use namespased modules
Constants:
create file: constants/store.js
export const LOGGING_SEARCH = 'logging search';
export const SEARCH = 'search';
then use it, e.g.:
import { LOGGING_SEARCH } from '../constants/store.js'
const actions = {
[LOGGING_SEARCH](state, query) {
log(...)
}
};
const logging = {
state: {},
mutations: {},
actions,
};
export default logging;
and call it
import { LOGGING_SEARCH } from '../constants/store.js'
store.dispatch(LOGGING_SEARCH, 'query');
namespased modules doc
store/logging.js
const actions = {
search(state, query) {
log(...)
}
};
const logging = {
namespased: true,
state: {},
mutations: {},
actions,
};
export default logging;
and call it
store.dispatch('logging/search', 'query');
Namespased modules are really helpfull especially with helpers

Related

How to Implement nuxtServerInit Action to load data from server-side on the initial load in Pinia (Nuxt3)

My Code:
export const useMenuStore = defineStore("menuStore", {
state: () => ({
menus: [],
}),
actions: {
async nuxtServerInit() {
const { body } = await fetch("https://jsonplaceholder.typicode.com/posts/1").then((response) => response.json());
console.log(body);
this.menus = body;
resolve();
},
},
});
NuxtServerInit is not working on initial page render on nuxt js vuex module mode.Anyone know this error please help me.
NuxtServerInit is not implemented in Pinia, but exists a workaround.
Using Pinia alongside Vuex
// nuxt.config.js
export default {
buildModules: [
'#nuxtjs/composition-api/module',
['#pinia/nuxt', { disableVuex: false }],
],
// ... other options
}
then Include an index.js file inside /stores with a nuxtServerInit action which will be called from the server-side on the initial load.
// store/index.js
import { useSessionStore } from '~/stores/session'
export const actions = {
async nuxtServerInit ({ dispatch }, { req, redirect, $pinia }) {
if (!req.url.includes('/auth/')) {
const store = useSessionStore($pinia)
try {
await store.me() // load user information from the server-side before rendering on client-side
} catch (e) {
redirect('/auth/login') // redirects to login if user is not logged in
}
}
}
}
In Nuxt2, the Nuxt will run the code in nuxtServerInit() of store/index.js on the server-side to boot the app.
However, in Nuxt3, there is no specific place to write the boot code, you can write the boot code anywhere instead of in nuxtServerInit() of store/index.js.
It might be helpful, especially when you need to send a request before boosting the app.
your pinia file may define like following:
store/menu.js
import { defineStore } from 'pinia';
export const useMenuStore = defineStore('menuStore', {
state: () => ({
_menus: [],
}),
getters: {
menus() {
return this._menus;
}
},
actions: {
async boot() {
const { data } = await useFetch('https://jsonplaceholder.typicode.com/posts/1');
this._menus = data;
}
}
});
Then, create a plugin which named as *.server.[ts|js], for example init.server.js
(.sever.js tail will let the file only run in server side)
plugins/init.server.js
import { defineNuxtPlugin } from '#app';
import { useMenuStore } from '~/store/menu.js';
export default defineNuxtPlugin(async (nuxtApp) => {
const menu = useMenuStore(nuxtApp.$pinia);
await menu.boot();
});
nuxt.config.js
modules: [
'#pinia/nuxt',
],
There is an entire example of SSR Nuxt3 with authorization that may help

Why vuex return object instead of array in Quasar App?

I have Quasar App
I connected vuex
I created a separate file as module for vuex like this:
I created an empty array in vuex
If I open Vue extension in browser I see that vuex return object where an array is stored instead of just an array
How can I store just an array instead of object?
I created a vuex file like this:
in store/index.js file I imported cars.js file:
import Vue from 'vue'
import Vuex from 'vuex'
import cars from "src/store/module-example/cars";
Vue.use(Vuex)
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({
modules: {
cars
},
// enable strict mode (adds overhead!)
// for dev mode only
strict: process.env.DEBUGGING
})
return Store
}
Cars.js file:
import axios from "axios";
const state = {
cars: []
}
const mutations = {
SET_CARS: (state, cars) => {
state.cars = cars;
}
}
const actions = {
async GET_ALL_CARS_FROM_API({commit}) {
let result = await axios.get('http://localhost:8050/api/cars');
commit("SET_CARS", result.data)
}
}
const getters = {
GET_ALL_CARS: (state) => {
return state.cars;
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
result.data is an object. In order to set cars to a plain array just set it to result.data.cars
commit("SET_CARS", result.data.cars)

Separating store into separate files (actions, mutations, getters) get api calls now not working

I'm trying to spilt up my store firstly so all the getters, actions and mutations are in separate files as per this answer: https://stackoverflow.com/a/50306081/5434053
I have API calls in a services file, the POST api calls seem to work but the GET ones do not, the action seems to get nothing back. Have I missed something?
import Vue from 'vue';
import Vuex from 'vuex';
import actions from './actions';
import getters from './getters';
import mutations from './mutations';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
status: '',
token: localStorage.getItem('token') || '',
user: {},
movie: {},
movies: {}
},
actions,
getters,
mutations,
});
store/actions.js
import axios from 'axios'
import {APIService} from '../services/APIService';
const apiService = new APIService();
let getMovies = async ({commit, state, getter}) => {
try {
await apiService.getMovies(localStorage.getItem('token')).then((data, error) => {
for (const movie of data.data.data.movies) {
movie.edit = false;
movie.deleted = false;
}
this.movies = data.data.data.movies;
console.log(data)
commit("fetch_movies", this.movies);
})
} catch(error) {
commit('auth_error')
localStorage.removeItem('token')
console.log(error)
}
}
export default {
getMovies,
};
It looks like you are importing actions from ./actions. However, when I look at your file at store/actions.js you are not exporting anything.
For JavaScript modules to work you have to add export statements to your files - so you can import the exported variables/properties somewhere else.
Also: You seem to only declare the function getMovies() without adding it to an actions object (which you import in store.js).
Try this:
// in store/actions.js
// your code..
const actions = {
getMovies,
}
export default actions;
Edit:
Just noticed you also use this in your action. If I am not mistaken it should be undefined as you only work with lambdas (Arrow Functions).

Correct setup and use of VUEX store mutation-types

I'm developing a Chrome extension using one of the Vue js boilerplates from Github. The default boilerplate setup is as follows:
store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import mutations from './mutations';
import * as actions from './actions'; // all actions are imported as separate vars
Vue.use(Vuex);
export default new Vuex.Store({
state: { },
mutations,
actions
});
Then in actions.js
import * as types from './mutation-types';
export const setFoo = ({ commit }, payload) => {
commit(types.SET_FOO, payload); // SET_FOO is defined in the mutation-types file
};
I think the above approach lacks a fundamental reason why we want to use mutation types file - to avoid retyping the names for mutations and actions.
So instead, I came up with a different approach:
store/index.js
...
import actions from './actions'; // actions are imported as separate functions
...
Then in actions.js
import * as types from './mutation-types';
export default {
[types.UPDATE_FOO] ({commit}, payload) {
commit(types.UPDATE_FOO, payload);
}
}
Then anywhere in the extension, we could also import mutation-types and dispatch actions using const names like so:
store.dispatch(types.UPDATE_FOO, 'some value');
The second approach seems to be more practical in terms of naming and then dispatching/committing our actions/mutations. Or could there be any issues with the latest?
Which of the above, would be generally better practice?
The first approach is preferable, but it's completely up to you. Similar approach is used in official Vuex docs.
Refrence
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// we can use the ES2015 computed property name feature
// to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
}
}
})
// actions.js
actions: {
checkout ({ commit, state }, products) {
// save the items currently in the cart
const savedCartItems = [...state.cart.added]
// send out checkout request, and optimistically
// clear the cart
commit(types.CHECKOUT_REQUEST)
// the shop API accepts a success callback and a failure callback
shop.buyProducts(
products,
// handle success
() => commit(types.CHECKOUT_SUCCESS),
// handle failure
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}

Vuex rootActions with several modules

I have a vuejs on client side, where I use vuex for state management. I have several modules (in separate files) but some of the modules, has very similar actions, that's why I want to create dry code.
My goal: Creating a root action, what can be called by every modules.
My main vuex looks like this:
export default new Vuex.Store({
actions: {
rootactions,
},
modules: {
users,
classes,
studentgroups,
// ... other stuff
}
})
How should I refer the rootactions methods?
Thanks for the responses in advance!
"To dispatch actions or commit mutations in the global namespace, pass { root: true } as the 3rd argument to dispatch and commit."
{
root: true
}
https://vuex.vuejs.org/guide/modules.html
How about to create a separate file RootActions.js with the common actions
export default {
action1: () => {
//
},
action2: () => {
//
},
}
And then import it in your module file e.g. User.js
import RootActions from './RootActions'
const state = {
// state object
}
const mutations = {
// mutations object
}
const actions = {
// actions object
}
export default {
namespaced: true,
state,
mutations,
actions: Object.assign(RootActions, actions)
}