VuexFire Mutations - vue.js

For anyone who has used VuexFire Vuex v2. What is mutations: VuexFire.mutations referring to here? The answer may be obvious but I have no idea what it means. Where do my actual mutations go then? I'm using Vuex v1 right now and it seems to be working fine but I would like to upgrade to using Vuex v2. Thanks!
var store = new Vuex.Store({
state: {
items: null
},
mutations: VuexFire.mutations, // What is this and where is it coming from??
getters: {
items: function (state) { return state.items }
}
})
new Vue({
el: '#app',
store: store,
computed: Vuex.mapGetters([
'items'
]),
firebase: {
items: db.ref('items')
}
})

I struggled with this one for a long while myself. Although I am not 100% sure of what the VuexFire.mutations does, I now understand that VuexFire is only in charge of getting your Firebase database data and correctly mutating your app state with that data.
So it seems that is the magical bit of code that make the local store's state mutation happen.
For your app to mutate / change Firebase database, you will still have to get the Firebase database reference and set / push / or whatever the data yourself.
For instance, using your code for illustration,
firebase: {
items: db.ref('items')
}
will let mutations: VuexFire.mutations 'know' what to mutate your app state with. But to mutate your Firebase database, you will have to do something like:
db.ref('items').push(WhateverNewData)
I hope this helps.

Related

I'm switching from Vuex to Pinia in Vue 3 and my unit tests are now failing. I can't seem to be able to create custom mock actions

Here's a simple example on the forgot password reset page of my app, I would want to bypass the server side and just have the password reset to succeed on click so I would write a test and use the custom test store like so:
const customStore = {
state() {
return {
Authentication: {
passwordResetSuccess: false,
},
};
},
mutations: {
SET_RESET_PASSWORD_SUCCESS(state) {
state.Authentication.passwordResetSuccess = true;
},
},
actions: {
forgotPasswordResetPassword() {
this.commit('SET_RESET_PASSWORD_SUCCESS');
},
},
};
Then I could include the custom store in my beforeEach() and it worked great. I've tried everything I can think of to get this to work with pinia, but it doesn't seem to work.
I'm using jest along with vue/test-utils.
I basically tried just creating the test pinia store, but I can't figure out how to get the component to use the custom test store.
const useCustomStore = defineStore('AuthenticationStore', {
state: () => ({
passwordResetSuccess: false,
}),
actions: {
forgotPasswordResetPassword() {
this.passwordResetSuccess = true;
},
},
});
const authenticationStore = useCustomStore();
I can't directly add it as a plugin because it can't find an active instance of pinia.
I went through this guide: https://pinia.vuejs.org/cookbook/testing.html#unit-testing-a-store
and I also tried using jest mock as described here: https://stackoverflow.com/a/71407557/4697639
But it still failed.
If anyone has any idea how to create a custom store that can be used by the component and actually hits the custom actions, I could really use some help figuring this out. Thank you!!
Tao mentioned in the comments that this isn't a good way to do unit tests. I will mark this as resolved and fix how I do the testing.

Can I change a Vuex store state for a layout from a component?

I am using Nuxt with vuetify.
Vuetify helpfully creates a drawer in the default layout (Pretty cool)
I would like to use a Vuex store to change the state of the drawer contained within the default layout from within a page or component.
I have the following in my store index.js
const createStore = () => {
return new Vuex.Store({
state: {
//Default State
showDrawer:false,
},
});
};
export default createStore
In my default layout I have
<v-navigation-drawer
v-if="$showDrawer.state.show"
Calling that directly works as expected, but is it possible from within a page to mutate the showDrawer state to true?
If so how, assuming its a mutation and committing the change through an action from what I have read but new to Vuex and would very much appreciate some guidance. I am sure there are better ways to solve this but keen to learn how to do this using Vuex if someone is able to offer an example.
Figured it out, in the page I add
beforeCreate() {
this.$store.commit('UPDATE_DRAWER', false);
}
And as a mutation I add
mutations: {
UPDATE_DRAWER(state, payload) {
state.show = payload
}
},
Thanks for looking, am sure I may be getting something slightly wrong still so feel free to let me know if what I am doing is incorrect, all helps with my learning :)

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;

Page reload causes Vuex getter to return undefined

Using Vue.js (Vuetify for FE).
A page reload causes the getter in Vuex to fail with pulling required data from the store. The getter returns undefined. The code can be found on GitHub at: https://github.com/tineich/timmyskittys/tree/master/src
Please see the full details on this issue at timmyskittys.netlify.com/stage1. This page has complete info on the issue and instructions on how to view the issue.
Note, there is mention of www.timmyskittys.com in the issue description. This is the main site. timmyskittys.netlify.com is my test site. So, they are the same for all intents and purposes. But, my demo of this issue is at the Netlify site.
I read the complete issue in the website you mentioned. It's a generic case.
Say, for cat details page url: www.timmyskittys.com/stage2/:id.
Now in Per-Route Guard beforeEnter() you can set the cat-id in store. Then from your component call the api using the cat-id (read from getters)
I found the solution to my issue:
I had to move the call of the action which calls the mutation that loads the .json file (dbdata.json) into a computed() within App.vue. This was originally done in Stage1.vue.
Thanks all for responding.
I had the same issue and my "fix" if it can be called that was to make a timer, so to give the store time to get things right, like so:
<v-treeview
:items="items"
:load-children="setChildren"
/>
</template>
<script>
import { mapGetters } from 'vuex'
const pause = ms => new Promise(resolve => setTimeout(resolve, ms))
export default {
data () {
return {
children: []
}
},
computed: {
...mapGetters('app', ['services']),
items () {
return [{
id: 0,
name: 'Services',
children: this.children
}]
}
},
methods: {
async setChildren () {
await pause(1000)
this.children.push(...this.services)
}
}
}
</script>
Even though this is far from ideal, it works.

Confused with Vuex commit/dispatch in simple VueJS test

From the book:
To invoke a mutation handler, you need to call store.commit with its type: store.commit('increment')
Mutations must always be synchronous.
From the book:
Actions commit mutations ( can be asynchronous )
Actions are triggered with the store.dispatch method: store.dispatch('increment')
So it's action -> mutation -> new state most of the time.
So what's confusing me, is the very simple example, whereby I'm trying to show the asynchronous result of an object getTest
See this pen
Why can't Vue see that I'm not calling a mutation, but an action when the component loads?
What is this "book" you are talking about? I'm asking because you are using a mix of new Vuex 2.* and old, Vuex 1.* syntax, which is not working anymore in 2.*, so I assume you are learning in part from outdated resources.
(Sidenote: Why are you using Vue 1? Vue2.* has been out for over 10 months now...)
Your action and mutation definitions are correct, but there's no vuex: {} key in components anymore in Vuex 2.*
Also, you are trying to dispatch an action 'INCREMENT', but oyour store only has a mutation by that name, no action. So you have to use commit rather than dispatch.
Instead, you directly add computed props and method to your instance, or use the map*helpers provided by Vuex:
var vm = new Vue({
el: '[vue=app]',
data: {
welcome: 'Testing Vuex'
},
store: myStore,
created() {
this.$store.dispatch(FETCH_TEST_STATE)
},
computed: {
...Vuex.mapState( {
count: state => state.count,
getTest: state => state.testState
}),
}
methods: {
increment({dispatch}) {
this.$store.commit('INCREMENT', 1)
}
}
})
the action you call from created doesn't work because async/await was acting up on codepen
the commit called from this action didn't set any state.
Fixing all of this, here's your working example:
https://codepen.io/LinusBorg/pen/NvRYYy?editors=1010