How to access Vuex store in Vue single file component - vue.js

I have a Quasar app running Vue 3 and Vuex 4
During app creation my store is accessible when printed and shows the full object. The store is set in app creation with
app.use(store, storeKey)
Which produces a fully hydrated object
{_committing: false, _actions: {…}, _actionSubscribers: Array(0),
_mutations: {…}, _wrappedGetters: {…}, …}
The vuex state works perfectly in my router/index with
export default route (function ({ store }) {
const isLoggedIn = store.state.auth.loggedIn;
This example correctly show the loggedIn value I set in my state, so I assume the vuex side must be setup correctly
My problem is I haven't been able to find a way to access my state from a Vue component
I tried with useStore() in my setup function
setup () {
const $store = useStore()
const loggedIn = computed({
get: () => $store.state.auth.loggedIn,
set: () => { $store.commit('login') }
})
Which produces a console error that
injection "store" not found.
and a loggedIn object of
ComputedRefImpl {dep: undefined, _dirty: true, __v_isRef: true,
effect: ReactiveEffect, _setter: ƒ, …}
I also tried using this.$store in the computed object
computed : {
loggedIn () {
return this.$store.state.auth.loggedIn
}
}
But I just get the error that
Property '$store' does not exist on type '{ loggedIn(): any; }'.
I assume I must be missing something silly. I just want to call $store.commit('login') or $store.dispatch from the single file component
How can I access my Vuex store from the single file .Vue component?
Per user10031694 I tried and got a reader working with mapState
computed : mapState({
loggedIn: state => state.auth.loggedIn,
Which gets {{loggedIn}} to show the correct field

Related

Store Vuelidate validation state (v$) in external store (Pinia, Vuex)

Vuelidate 2 (aka "Next") is supposed to support using Vuelidate outside of Vue components. I'd like to store a global validation state (v$) in a Pinia store instead of in one or more components, using a mapped state property. One of the authors offered an example for doing this with the Composition API, where you pass a reactive state to useVuelidate():
const formState = reactive({})
const rules = {}
const state = {
someProperty: '',
validations: useVuelidate(rules, formState)
}
export {
state
}
I'm still using the Options API and Vue 2, but haven't been able to figure out to "translate" the above for the Options API. I've tried passing mapped state properties, but they get flagged as "undefined". E.g., something like this in my root component (note: you have to install the CompositionAPI module and use setup to use Vuelidate 2 in Vue 2):
setup: () => ({
v$: useVuelidate(this.mappedValidationRulesObject, this.mapped.StoreState)
})
Does anyone know how to do this?

NUXTJS share JS method with Store Getters

I want to write a simple JS method that I will use both in Store GETTERS.
I created a new file: /plugins/myMethod.js and added it to nuxt.config.js (at plugins part).
Follows the content of the file:
export default ({ app }, inject) => {
// Inject $hello(msg) in Vue, context and store.
inject('exportaData', msg => console.log(`Data is: ${msg}!`))
}
I can use this method in Vue Components and in store ACTIONS, but not in Store GETTERS. I tried this.$myMethod(1) without any success.
Follows the code of store/data.js
export const getters = {
hoje: state => {
console.log('Running getter HOJE')
this.$exportaData('12345')
},
}
and in my Vue component:
<p>DATA: {{ $store.getters['datas/hoje'] }}</p>
Any idea how to access my custom method in the store getter?
Thanks

nuxt, ...mapState value is returned as undefined

I fetch an api in my page's fetch() hook and then through an action and a mutation I update a value in my state called movieList. I know actions and mutations work because I can see them logging the response object correctly. But my page doesn't seem to find movieList in my store so it returns undefined. This is my folder structure:
This is my state:
const state = () => ({
movieList: 'pashmi'
});
pelase note I initialized movieList: 'pashmi' to test to see if ...mapState returns pashmi or not but it still returns undefined. This is my mapState:
import { mapState } from "vuex";
computed: {
...mapState("movies", ["movieList"]),
}
Rename movies.js to index.js, should work.

How to watch on Route changes with Nuxt and asyncData

Hi everybody i'm trying to watch on route changes in my nuxt js app.
Here my middleware:
export default function ({ route }) {
return route; but i don't know what to write here
}
index.vue File
middleware: [routeReact]
i'm trying to write this:
app.context.route = route
but it says to me that app.context doesn't exist
Here's the point of my question i'm trying to update my data that gets from my api with axios on page if route changing
like this
this the page
i'm clicking link to next page :
but when i'm route to next page, nothing happens all data is the same:
here my asyncData code:
asyncData({ app }) {
return app.$axios.$get('apps/' + app.context.route.fullPath.replace(/\/categories\/?/, ''))
.then(res => {
return {
info: res.results,
nextPage: res.next,
prevPage: res.prev
};
})
}
Thanks for your help
First thing, context.route or it's alias this.$route is immutable object and should not be assigned a value.
Instead, we should use this.$router and it's methods for programmatic navigation or <nuxt-link> and <router-link>.
As I understand, you need to render the same route, but trigger asyncData hook in order to update component's data. Only route query is changed.
Correct way to navigate to the same page but with different data is to use link of such format:
<nuxt-link :to="{ name: 'index', query: { start: 420 }}"
Then you can use nuxt provided option watchQuery on page component and access that query inside asyncData as follows:
watchQuery: true,
asyncData ({ query, app }) {
const { start } = query
const queryString = start ? `?start=${start}` : ''
return app.$axios.$get(`apps/${queryString}`)
.then(res => {
return {
info: res.results,
nextPage: res.next,
prevPage: res.prev
}
})
},
This option does not require usage of middleware. If you want to stick to using middleware functions, you can add a key to layout or page view that is used. Here is an example of adding a key to default layout:
<nuxt :key="$route.fullPath" />
This will force nuxt to re-render the page, thus calling middlewares and hooks. It is also useful for triggering transitions when switching dynamic routes of the same page component.

VueJS - requiring and rendering a component programmatically

I have a bit of a specific usecase here. I have a large Vue app with lots of pages. Each page has a page-id to identify it on the server and load it's content. These ids are in the router path (parent-id/child-id/another-child-page-id). On the page components themselves I display a page title. Unfortunately, there is no correlation between the translation key of the page title to the page-id.
Now, instead of creating a mapping between page-ids and page title translations that I will have to maintain by hand, I figured I could lookup the route in the router config and require the component:
{
path: 'the-page',
name: 'ThePage',
component: resolve => require.ensure([], () => resolve(require('#/pages/ParentPage/ChildPage/ThePage')), 'parent-page')
}
This works by recursively walking through the routes to find the page-id, then loading the component in a promise:
// find the route definition
const route = findRouteByPath(file.areaName)
// load the route component
new Promise(resolve => { route.component(resolve) })
.then(component => {
console.log(component)
})
This gives me the component like so:
Object {
mixins: Array(1),
staticRenderFns: Array(0), __file: "/the/file/path.vue",
beforeCreate: Array(1),
beforeDestroy: Array(1),
components: Object,
mixins: Array(1),
render: function (),
// etc.
}
If I call the render function, I get an error:
Uncaught (in promise) TypeError: Cannot read property '_c' of undefined
What I want to do is programmatically render the component and grab the content of the slot page-title from the component.
Can anyone help with this?
Update 1
Vue.extend() then mounting seems to do what I want. The problem is, I get all kinds of errors because the pages depend on certain things being around, like the current route. I'm also a bit worried to trigger certain created() hooks that would trigger API calls and such. My current state is trying to get rid of mixins and hooks like so:
const strippedComponent = Object.assign(component, {
mixins: [],
components: {},
beforeCreate: []
})
const Constructor = Vue.extend(strippedComponent)
const vm = new Constructor({})
But I'm not quite there yet.
Update 2
I ended up abandoning this and bit the bullet by adding a meta: {} object to each route where I store things like the page title translation key and other good stuff.