How to set up vuexfireMutations in Vuex store.js file - vue.js

I am attempting to build a Vue.js application that utilizes Vuexfire in the store.js file. My store.js file looks something like this:
import Vue from 'vue'
import Vuex from 'vuex'
import { vuexfireMutations, firestoreAction } from 'vuexfire'
import { db } from '#/main'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
items: []
},
mutations: vuexfireMutations,
actions: {
setEvents: firestoreAction(context => {
return context.bindFirestoreRef('items', db.collection('dbItems'))
}),
},
})
I understand from the documentation that the .bindFirestoreRef() method is what binds Firestore to the Vuex store, while firestoreAction is a wrapper that injects .bindFirestoreRef() into the context object, so that it can be used as a method of the store (along the same lines as the commit method). The payload is then committed to mutations, while vuexfireMutations apparently handles the mutation of the state behind the scenes. Does this mean that vuexfireMutations is a method? What is the right term to describe vuexfireMutations? I really don't feel like the documentation explains very well what this imported item is. I'm just kind of having to guess that it is something that handles mutations, but what is the right term for it?

Related

Using Vuex State in main js

I am trying to use my store state in main.js but it vanishes my component, can I use state in mian.js
Axios.defaults.headers.common['BranchId'] = this.$store.state.myBrachId,
if not what how can I set the default headers dynamically then..?
You're asking how to access a Vuex store outside a Vue component. The syntax that you're currently using is only valid if you're writing a Vue component.
In case you want to access Vuex outside (any .js file) you should, first, export the store. Then, import that store in your file and finally use the store as you place.
Let's see an example:
store/index.js
export const store = new Vuex.Store({
state () {
myBrachId: 'niceBranch007'
}
});
Then, in any other .js file (main.js in your case)
import { store } from 'store/index.js'
console.log(store.state.myBrachId)
If you're trying to add headers to axios I'd ask you to consider if you should really be getting that header data from a Vuex store anyways. Remember that any browser refresh will clear your store so you should not rely on it's availability more than you need to. Using localStorage or sessionStorage might be better for what you're looking to do here.
I am doing this right now this is my store
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
branchId: "",
},
getters:{
},
mutations: {
},
actions: {},
modules: {}
});
In header cmponent
this.$store.state.branchId = this.Branches[index].branchId;
in main js
import Axios from 'axios'
import { store } from './store/index'
Axios.defaults.headers.common['BranchId'] = store.state.branchId;
this is not setting axios header, it comes empty

Vue.js Vuex cannot access store in router

I've seen that this question have been asked a couple of time but I cannot find any good answer and don't understand why my code is behaving like this.
As said in the title I'm trying to import my store in the router to be able to use my getters on conditional and grant a user to access or not a route.
But as soon as i'm trying to import the store I get the following error:
[vuex] unknown action type: autoSignIn
this is coming from:
const vm = new Vue({
router,
store,
provide,
i18n,
render: handle => handle(App),
created () {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$store.dispatch('autoSignIn', user)
this.$store.dispatch('loadMatter')
this.$store.dispatch('loadFootprints')
this.$store.dispatch('loadMembers')
}
})
So I guess that when my app is starting the store hasn't loaded yet.
How can I workaround that I want to be able to use
store.getters.mygetter
Thank you very much
I think you need to import your store in your router file
I'm doing it like this:
import store from "#/store/index.js";
Are you using modules of vuex?
Can you share your store index file?
https://vuex.vuejs.org/guide/modules.html
If you are using modules of vuex, you should do this.$store.dispatch('module_name/action_name')
I have my store split into files
Vue.use(Vuex);
const store = new Vuex.Store({
state,
actions,
mutations,
getters,
plugins: [
process.env.NODE_ENV === 'development' && createLogger({ collapsed: false }),
].filter(Boolean),
});
export default store;

How can I break my Vuex actions into multiple files and still use `dispatch`?

I have broken my actions into multiple files to make my project more maintainable and extensible. Trying to dispatch from one action to another, however, is not working.
My file tree looks like this:
store.js
actions
|--actions.js
|--createShape.js
|--addShape.js
My store.js looks like:
import actions from './actions/actions'
const PlaypadStore = {
namespaced: true,
state: {
localState: ''
},
actions: {
...actions,
},
}
My actions.js folder has the following:
import CREATE_SHAPE from './createShape';
import ADD_SHAPE from './addShape';
export default {
CREATE_SHAPE,
ADD_SHAPE,
}
The problem is trying to dispatch ADD_SHAPE from CREATE_SHAPE. My createShape.js looks like the following:
const CREATE_SHAPE = ({ state, dispatch }) => {
return dispatch('ADD_SHAPE')
}
export default CREATE_SHAPE;
But it returns me this:
[vuex] unknown local action type
The question is this: how can I break my actions into multiple files, but still be able to dispatch actions from one to another?
if you use 'export default...' in your action-files and import your files in the store like that:
import actions_one from './actions_one';
import actions_two from './actions_two';
you can then use the spread operator to make it like you're importing one object:
export default new Vuex.Store({
namespaced: true,
actions: {
...actions_one,
...actions_two
},
...
you need to let Vuex know that actions.js, createShape.jsand addShape.jsare "modules" of your store for this to work.
You can read more about it in the Vuex Modules documentation.
Basically you need an index.js file declaring the modules at the root of your store. That should look like this:
import actions from "./actions";
import createShape from "./createShape";
import addShape from "./addShape";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
actions,
createShape,
addShape
}
});
At this point your dispatch call should work, UNLESS it comes from another vuex store module, in that case just specify "root = true" as they pointed out here.

Vuex module not accessible from rootState

I needed to get route's query parameters inside Vuex in order to preload filter settings and update the state of the application. To make this possible I installed vuex-router-sync.
Next step was to synchronize the Vuex and VueRouter.
Router:
Vue.use(VueRouter);
export default new VueRouter({ mode: 'history' });
Store:
Vue.use(Vuex);
export default new Vuex.Store({
modules: { filters: FiltersModule },
plugins: [ FiltersPlugin ]
});
App's bootstrap:
const unsync = sync(store, router);
new Vue({
el: '#restaurant-admin-app',
components: {
'App': AppComponent,
'filters': FilterComponent,
'orders-table': OrdersTableComponent
},
store,
router
});
My FilterPlugin that should trigger the URL parsing:
export default store => {
store.dispatch('filters/parseURLFilterSettings');
}
And now, the funny part, here's the URL parsing action:
parseURLFilterSettings: ({ state, commit, rootState }) {
console.log('RootState:', rootState);
console.log('Route module (incorrect):', rootState.route);
console.log('Filters module (correct):', rootState.filters);
console.log('Object\'s keys:', Object.keys(rootState));
}
What am I doing wrong? I thought it might be something with syncing, but at the end the console.log shows clearly that the route Object is there (and it's not empty), but somehow when I access it, it's undefined. Thank you in advance.
The problem was very well explained here. What it basically says is that the object's value is evaluated when you open it's body in the console.
The problem was I didn't have the route module loaded yet, because I was trying to dispatch an action from a vuex plugin which seems to load before the vuex-router-sync's syncing was done.
The problem was solved when I moved application's bootstrap logic from vuex plugins into the AppRootComponent's mount lifecycle event.
You should import the router-sync. After that your store and routes wil behave properly. I usually do this in the main.js file.
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
sync(store, router)

How to access Vuex module getters and mutations?

I'm trying to switch to using Vuex instead of my homegrown store object, and I must say I'm not finding the docs as clear as elsewhere in the Vue.js world. Let's say I have a Vuex module called 'products', with its own state, mutations, getters, etc. How do I reference an action in that module called, say, 'clearWorking Data'? The docs give this example of accessing a module's state:
store.state.a // -> moduleA's state
But nothing I can see about getters, mutations, actions, etc.
In Addition to the accepted answer I wanna provide you with a workarround for the getter which is missing in the answer.
Debug the Store
In any case you can call console.log(this.$store) to debug the Store.
If you do so you will see the getters are prefixed with the namespace in their name.
Access namespaced getter
this.$store.getters['yourModuleName/someGetterMethod']
Dispatch namespaced
this.$store.dispatch('yourModuleName/doSomething')
Dispatch namespaced with params
this.$store.getters['yourModuleName/someGetterMethod'](myParam)
Conclusion
The key is to handle the namespace like a file System like Justin explained.
Edit: found a nice library for handling vuex Store
In addition to the basic knowledge I'd like to add this vuex library as a nice addition for working effectivly and fast with the vuex store. https://github.com/davestewart/vuex-pathify .
It looks pretty interesting and cares much of the configuration for you and also allows you to handle 2waybinding directly with vuex.
** Edit: Thanks to the other Answers. Added Dispatching method with params for wholeness.
In your example it would be store.dispatch('products/clearWorkingData') you can think of actions/mutations as a file system in a way. The deeper the modules are nested the deeper in the tree they are.
so you could go store.commit('first/second/third/method') if you had a tree that was three levels deep.
As another addition to the accepted answer, if you need to pass parameter(s) to the getter (for instance to fetch a specific item from the store collection), you need to pass it as follows:
this.$store.getters['yourModuleName/someGetterMethod'](myParam)
I don't think I like this notation very much, but it is what it is - at least for the moment.
Try this approach!
getCounter(){
return this.$store.getters['auth/getToken'];
}
auth is my module name and getToken is my getter.
Using Vuex mapGetters and mapActions you can now do this pretty easily. But I agree, it still isn't very obvious in the documentation.
Assuming your store module 'products' has a getter called 'mostPopular' and an action called 'clearWorkingData':
<template>
<div>
<p>{{mostPopularProduct}}<p>
<p><button #click="clearProductData">Clear data</button></p>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
computed: mapGetters({
mostPopularProduct: "products/mostPopular"
}),
methods: mapActions({
clearProductData: "products/clearWorkingData"
})
}
</script>
The mapGetters helper simply maps store getters to local computed properties:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// mix the getters into computed with object spread operator
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
If you want to map a getter to a different name, use an object:
...mapGetters({
// map `this.doneCount` to `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
You have to be aware of using namespaced: true when configuring particular store object
In Addition to the accepted answer, I feel it's not a good idea to mutate the state and commit the mutation directly in component. Thumb rule I follow is, Always use an action to commit the mutation and state only mutate inside mutations.
Use getters to get a transformed state.
Getters can be mapped to computed using mapGetters and actions can be mapped to methods using mapActions as below example
// component.vue
// namespace_name=products
<template>
<div>
<p> This is awesome product {{getRecentProduct}} </p>
</div>
<button #click="onButtonClick()"> Clear recent</button>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
computed: {
...mapGetters({
getRecentProduct: "products/getRecentProduct",
}),
anotherComputed(){
return "anotherOne"
}
},
methods: {
...mapActions({
clearRecentProduct: "products/clearRecentProduct",
}),
onButtonClick(){
this.clearRecentProduct(); /// Dispatch the action
},
anotherMethods(){
console.log(this.getRecentProduct); // Access computed props
}
}
};
</script>
Here's how you can access vuex Getters & Mutations using Composition API (setup)
<script setup>
import { useStore } from 'vuex'
const store = useStore();
var value = store.getters['subModuleName/getterMethod'];
store.commit['subModuleName/MutationMethod'];
</script>