How to do getter with parameter using vuex-module-decorators? - vuex

I'm trying to implement a vuex getter function (with parameter) using the Typescript/ES7 Decorators provided by vuex-module-decorators.
the normal vuex implementation would look like this:
export default new Vuex.Store({
state: {
students: []
},
getters: {
findStudent: state => id => state.students.find(s => s.id == id)
}
})
The vuex-module-decorators style guide says to use Typescript getter accessor
#Module
class MyModule extends VuexModule {
students = []
get findStudent(id) {
return students.find(s => s.id == id)
}
}
Therefor, of course my linter complains A 'get' accessor cannot have parameters
What would then be the best practice to implement such getter? Or should do the logic of such function into my vue component?

From github
Return a function from the getter
get getUser() { return function (id: string) { /* ... */ } }

Related

vue3 resuable computed properties

I tried creating Singleton service files with vue3 to have reusable computed properties (define once , then just reuse on every other call)
Normally with composition api pattern each time you do useX() every computed property inside is is redefined, this is ok for small project with little amount of computed props but for my scenario many computed props are reused on multiple components
so here what I did :
function factory(){
const x = computed(()=> store.getters['x']);
function updateX(){
store.commit('setX',newXValue);
}
return { x };
}
export default function useY() {
return SingletonServiceProvider.Create<ReturnType<typeof factory>>(factory);
}
export default class SingletonServiceProvider {
static Create<T>(factory: (...args: unknown[]) => T): T {
// TODO define proper type
// #ts-ignore
if (!factory.Instance) {
// #ts-ignore
factory.Instance = factory();
}
// #ts-ignore
return factory.Instance;
}
}
Now the problem I am facing: the x prop is properly filled the first time. But If I change the store value the x computed property is not updated!!!
I even added a store.watch and even this is nor triggered too!!
store.watch(
(state, getters) => getters['x'],
(value, oldValue) => {
console.log('...................xxxxx', { ...value }, { ...oldValue });
},
);
What am I doing wrong? Is this a vue/vuex limit ?

Vuex Getter Hook with Params

I defined a vuex getter function with parameter like this:
const getters = {
getProjectById: (state) => (id) => {
return state.projects.find(project => project.id === id)
}
}
Now, i want to use this getter in my component, but i couldn't find a way to pass the parameter to the getter.
Here is my getter hook computed property:
computed: {
...mapGetters(["currentUserPhoto","getProjectById"])
},
Is it possible to pass Id parameter which is come from router, to "getProjectId" getter? If is possible, what is the best way to do it?
Add another computed property called projectById which takes the route param as parameter and returns the project :
computed: {
...mapGetters(["currentUserPhoto","getProjectById"]),
projectById(){
return this.getProjectById(this.$route.params.id)
}
},

Vuex getters with params

I am wondering why can't I use vuex getter with property with default value like this:
getters: {
getTest: (state, property = 'current') => {
return state.test[property]
}
}
and when I use it like this getTest.includes('something') it doesn't work but if I use it like this getTest().includes('something') it works?
Since when there are no params used it works without ()
https://vuex.vuejs.org/guide/getters.html#method-style-access
getters: {
getTest: (state) => (property = 'current') => {
return state.test[property]
}
}
// example usage
this.getTest().includes('something')
The second argument of the getters is the other getters :
Getters will also receive other getters as the 2nd argument
(https://vuex.vuejs.org/guide/getters.html#property-style-access)
So your property parameter will be an array, thus state.test[property] always returns undefined
To use a getter as a function with parameters, you need to make your getter return a function, as shown here: https://vuex.vuejs.org/guide/getters.html#method-style-access
getters: {
getCarteiraPeloId: (state) => (id) => {
return state.carteiras.find(thing => thing.id === id) || { nome: 'Não Encontrado' }
}
That is it.

Use getter in the same module in which it was created

Is it possible to initialize state's property using getter which was created in the same module? Something like this:
export const gamesModule = {
state: {
games: [],
selectedGameID: null,
playerOnTurnID: this.getters.getSelectedGame.playerData[0]
},
getters: {
getGames: state => state.games,
getselectedGameID: state => state.selectedGameID,
getSelectedGame: state => getSelectedGameById(state.games, state.selectedGameID),
},
mutations: {
SET_GAMES (state, game) {
state.games.push(game);
},
SET_SELECTED_GAME_ID (state, id) {
state.selectedGameID = id;
},
SET_PLAYER_ON_TURN_ID (state, playerID) {
state.playerOnTurnID = playerID;
}
},
actions: {
async createGame({ commit }) {
try {
const { data } = await gameService.createGame();
commit('SET_GAMES', data);
} catch (error) {
console.warn('Error creating new game: ', error);
}
},
setSelectedGameID({ commit }, id) {
commit('SET_SELECTED_GAME_ID', id);
},
};
Written like this, it does not work because getters are undefined.
this does not exist in an object's context, and is only really applicable in constructor functions or classes.
I see two problems here.
First of all, you can't reference the object itself, because it hasn't been defined yet. You would have to create a local variable before declaring the object that would have the common property, in this case, the getter function.
Second of all, more importantly, I'm not sure it would help to access the getter (Reducer) function, as it has no knowledge of the state, which is passed to it as the first parameter by the underlying Vuex library when processing mutations (Actions).
Vuex is based upon the Redux pattern, Action -> Reducer -> Store, I would recommend reading it a quick introduction on how Redux works, as it will help you understand a lot better the action flow inside of Vuex.

Vue make ES6 class object reactive

I have a ES6 class that I use to hold and manage datas:
import DataManager from "./components/data-manager.js";
export default {
...
data() {
return {
dataModel: null
}
},
beforeMount() {
this.dataModel = new DataManager();
},
computed: {
datas() {
return this.dataModel.myProperty
}
},
...
}
But it appears that there is a reactivity issue and any changes made into that dataModel does not trigger the re-rendering of the view.
How can I make the properties of my class reactive ?
Thanks,
Edit: #acdcjunior The Class looks like this, but I realize that some mutation occurs... would that be the issue ? Anyway if thats not good practice to make a whole ES6+ class reactive, I'll get ride of that and go for a plain Object, or even Vuex store. Any simple suggestion ?
class DataManager {
constructor() {
this.professionalsList = [];
this.eventsList = [];
this.attendeesList = [];
}
// import datas
importDatas({
professionalsList,
eventsList,
attendeesList
}) {
this.professionalsList = this.parsePros(professionalsList)
...
}
parsePros(list) {
return list.map( item => { ... })
}
...
}
Edit #2: So the issue was indeed some mutations that occures in one of the objects I was trying to bind.
You need to store the same data structure in data().dataModel as returned from DataManager() and change every property in methods. When you setting new dynamic property in data object they can't be reactive. You can try Vue.set(), but it's a bad practice.