Vuex state getter not working inside the vue 3 composition api - vue.js

Trying to implement the new Vue composition API I ran into an issue, my vuex state values are not working and it will return an $store undefined error. When I check if my language state is set it is set so theres data present. I could not find any good information about this but I did find some helper plugin but I dont want to use plugins for every issue so is there a way to do this?
I am using vue 3 with vuex 4
export default {
setup (props, context) {
console.log(context.root.$store.getters['i18n/language'])//not working
// more logic here
}
}

You should use the composable function called useStore to get the store instance :
import {useStore} from 'vuex'
export default {
setup (props, context) {
const store=useStore()
console.log(store.getters['i18n/language'])
}
}

Related

How to correctly set up Cypress 10, Vue2, Vuetify, Composition API for component testing?

The guide is quite confusing and obviously not correct when trying to set up Cypress 10 for component testing with Vue2 and Vuetify with composition API. There's lots of errors of unknown tags, things returned from setup() aren't accessible, spread operators where there shouldn't be, imports that don't work etc. What's the correct way to set things up so testing works?
You need to set up Vuetify as regular, to the global Vue object. Then in the mount you need to give the Vuetify object to the mount function so it can be found by the components. When using Composition API that also needs to be set up regularly to the global instance (unlike Vuetify it also works in the local instance, if you want).
Then mount the component inside a v-appso it should work properly and pass arugments around.
So component.ts file will include this:
import { mount } from 'cypress/vue2'
import Vuetify from 'vuetify'
import VueCompositionAPI from '#vue/composition-api';
import Vue from 'vue'
import { VApp } from 'vuetify/lib/components/VApp';
Vue.use(Vuetify);
Vue.use(VueCompositionAPI);
Cypress.Commands.add('mount', (component, args) => {
args.vuetify = new Vuetify(yourVuetifyOptions);
return mount({ render: (h) => h(VApp, [h(component, args)]) }, args);
})
When using the mount just do:
cy.mount(myComponent, { props: {someProp: 123 } });
If you need to set up plugins for the local Vue instance in the test they need to be set in args.extensions.plugins, the guide seems to mention globals but that is incorrect.
cy.mount(myComponent, { props: {someProp: 123 }, extensions: { plugins: [MyPlugin] } });
Note that I'm using args for both settings parameters for mount and also for the component, if needed those two can be separated. But there shouldn't be much clashing of properties and attributes so this works.
Also the props/attributes/etc for the component must be given as they're given to createElement, not mount (so props instead of propsData etc).

Redirecting users after an action

I am trying to achieve having a redirection if the user logs in successfully. I was trying to call this.$router.push('/profile') with then the call back after login however I get an error stating Error Cannot read properties of undefined (reading '$router') I am not sure if there is a new flow to how to get this done since I am using composition with <script setup> syntax. I read the document reference online but still not seeing anything concrete as to how to do this type of navigation now. How can I achieve this with the new vue3 composition api? It seems I am missing something.
If you use setup() inside the script, you can't access the router with $router.
if you use vue3, this code can help you:
<script>
import { defineComponen } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
setup() {
const router = useRouter()
function login() {
router.push('/profile')
}
return {
login
}
}
})
</script>

How to use Vuex through the setup function in Storybook

I am currently struggling with Vuex in Storybook. I use it through const store = useStore() in the setup function.
However I didn't find a way to inject a custom store into the component.
I can surely inject a store globally in the storybook preview.js config file as follow:
import { app } from '#storybook/vue3';
import store, { key } from '#/store';
app.use(store, key);
Is there a way to create custom stores for stories of components that are using the composition API (useStore() to get to Vuex) ?

What is an equivalent of `created()` in the Vue.js composition api?

Could you advise what is the equivalent of the created() in the new Vue composition API, which I'm using from within Vue2 like this:
import { reactive, toRefs } from '#vue/composition-api'
From the Composition API docs on Lifecycle Hooks:
Because setup is run around the beforeCreate and created lifecycle hooks, you do not need to explicitly define them. In other words, any code that would be written inside those hooks should be written directly in the setup function.
Anything you would have done in the created hook you can do in setup.
to help the community, the created() method can be used this way.
hope this helps :)
<script>
import TenantsAPI from "#/api/tenants";
export default {
setup() {
const tenantsAPI = new TenantsAPI(); //compositon api
};
}
//options api
//async created(){
// this.tenantsAPI = new TenantsAPI();
//}
</script>

How to access Vuex from Vue Plugin?

How can I access my store from my plugin? Console returns undefined.
import store from './store';
export default {
install(vue, opts){
Vue.myGlobalFunction = function(){
console.log(store);
}
}
}
I recently had to do this too to make a pouchDb plugin, and came up with a new way.
When you create your first Vue object, you can do this.
import PouchDb from '#/pouch_db/PouchDbPlugin'
let DefaultVue = Vue.extend({
components: {App},
store,
created () {
Vue.use(PouchDb, this.$store) // Create it by passing in the store you want to use
}
})
My plugin adds an additional store, and it's own mutations and getters.
export default {
install (Vue, store) {
store.registerModule('PouchDb', pds)
const pouchDb = new PouchDb(store)
Vue.pouchDb = pouchDb
Vue.prototype.$pouchDb = pouchDb
}
}
Inside the constructor, I store the store
class PouchDb {
constructor (store) {
this.store = store
// ... etc.
}
// ... more functions
}
And then use it in other functions
class PouchDb {
// ... constructor and other functions
async addSync (docId) {
this.store.dispatch('PouchDb/addSync', docId)
}
}
It's a bit of a cheat to pass in the store, but seems to work nicely. It's usable throughout the app like this
// Inside vuex store
Vue.pouchDb.addSync(// ...etc)
// inside component
this.$pouchDb.removeSync(// ...etc)
See official guide here where it states
A Vue.js plugin should expose an install method. The method will be called with the Vue constructor as the first argument, along with possible options:
So you can do this, very easily.
Vue.use( {
install(Vue){
Vue.prototype.$something = function (){
this.$store...etc
}
}
} )
To use, simply do this.$something() in a components methods/computed etc, or directly in the component markup as {{$something()}}
This will remove the plugin needing to know where the store actually resides, while still allowing you to utilize the store within the plugin.
This is because it will inherit the scope of whatever component utilizes it, thus providing access to all of the components instance properties, including things like $store, $router as well any of it's local properties such as computed properties, parents etc. Essentially the plugin functions as if it is directly a part of the component (eg if you used it as a mixin).
For Vue 3
Incase if you wonder, how to do it in Vue 3, You can use the following.
plugin.js
export default {
install(app) { // app instance
console.log(app.config.globalProperties.$store)
}
}
main.js
import store from './pathtostore'
import plugin from './plugin'
createApp(...).use(store).use(plugin)
When app starts, you import your store and "append" it to Vue, globally.
Now, if you use() your plugin, the first parameter of install() is always Vue itself, and in this moment Vue already has access to the store, in the install method you can simply start
install(vue, opts) {
... here your can acces to vue.$store ....
}