NUXTJS share JS method with Store Getters - vue.js

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

Related

How to access Vuex store in Vue single file component

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

Importing a Vue library in nuxt.js via plugins

Any idea how I'm going to use this plugin? https://github.com/DimanVorosh/vue-json-rpc-websocket/blob/e2199d89dc15f50e57e7c5c70adfd95e5ceb5cda/src/wsMain.js
I see that it is auto registering with vue but I can't use it in nuxt.
I created the plugins/vue-json-rpc-websocket.client.js, registered in nuxt.config.js as
'~/plugins/vue-json-rpc-websocket.client.js'
but I have no idea what to write in the inject method and IF I have to do it to make it work. this.$socket is undefined in component.
import Vue from 'vue'
import JRPCWS from 'vue-json-rpc-websocket'
Vue.use(JRPCWS, 'wss://bsc-ws-node.nariox.org:443', {
reconnectEnabled: true,
reconnectInterval: 5000,
reconnectAttempts: 3
})
// do I need this?
export default ({ app }, inject) => {
// Inject $hello(msg) in Vue, context and store.
// inject('hello', msg => console.log(`Hello ${msg}!`))
}
also, any idea how can I ENV the 'wss://bsc-ws-node.nariox.org:443' string?
Totally working on my side with the package that you're using and your given configuration. No need to inject anything so far!
Here is a fresh repo created for the example: https://github.com/kissu/so-nuxt-json-rpc-websocket
The below screenshot is using a console.log(this.$socket) in a mounted hook in /pages/index.vue but you can also use $vm0 and access the instance directly from the devtools after selecting the root component (in the screenshot too).
For the env variables part, you can create an .env file at the root of your directory like this
WS_URL="wss://echo.websocket.org"
// nuxt.config.js
export default {
publicRuntimeConfig: {
wsUrl: process.env.WS_URL,
},
}
Then, use this variable in your plugin like this
import Vue from 'vue'
import JRPCWS from 'vue-json-rpc-websocket'
export default ({ $config: { wsUrl } }) => {
Vue.use(JRPCWS, wsUrl, {
reconnectEnabled: true,
reconnectInterval: 5000,
reconnectAttempts: 3
})
}

Make Vue data globally available and accessible for all components

In have a simple Vue cli app with some pages.
In Users.vue I fetch the data from an API with axios:
<script>
import axios from 'axios'
export default {
data() {
return {
users: []
}
},
mounted () {
axios
.get('https://api.github.com/users')
.then(response => (this.users = response.data))
}
}
</script>
This works fine. I can access the properties.
But how do I add axios and the mounted hook globally e.g. to App.vue and be able to access the data from the json in every component?
In order to use the data from everywhere in your application. you should save it in store. using vuex. https://vuex.vuejs.org/
another way could be fine too, in case you need the data just in user's children. you can simply pass the data by using props https://v2.vuejs.org/v2/guide/components-props.html

Vue/Nuxt: How to define a global method accessible to all components?

I just want to be able to call
{{ globalThing(0) }}
in templates, without needing to define globalThing in each .vue file.
I've tried all manner of plugin configurations (or mixins? not sure if Nuxt uses that terminology.), all to no avail. It seems no matter what I do, globalThing and this.globalThing remain undefined.
In some cases, I can even debug in Chrome and see this this.globalThing is indeed defined... but the code crashes anyway, which I find very hard to explain.
Here is one of my many attempts, this time using a plugin:
nuxt.config.js:
plugins: [
{
src: '~/plugins/global.js',
mode: 'client'
},
],
global.js:
import Vue from 'vue';
Vue.prototype.globalFunction = arg => {
console.log('arg', arg);
return arg;
};
and in the template in the .vue file:
<div>gloabal test {{globalFunction('toto')}}</div>
and... the result:
TypeError
_vm.globalFunction is not a function
Here's a different idea, using Vuex store.
store/index.js:
export const actions = {
globalThing(p) {
return p + ' test';
}
};
.vue file template:
test result: {{test('fafa')}}
.vue file script:
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions({
test: 'globalThing'
}),
}
};
aaaaaaaaand the result is.........
test result: [object Promise]
OK, so at least the method exists this time. I would much prefer not to be forced to do this "import mapActions" dance etc. in each component... but if that's really the only way, whatever.
However, all I get is a Promise, since this call is async. When it completes, the promise does indeed contain the returned value, but that is of no use here, since I need it to be returned from the method.
EDIT
On the client, "this" is undefined, except that..... it isn't! That is to say,
console.log('this', this);
says "undefined", but Chrome's debugger claims that, right after this console log, "this" is exactly what it is supposed to be (the component instance), and so is this.$store!
I'm adding a screenshot here as proof, since I don't even believe my own eyes.
https://nuxtjs.org/guide/plugins/
Nuxt explain this in Inject in $root & context section.
you must inject your global methods to Vue instance and context.
for example we have a hello.js file.
in plugins/hello.js:
export default (context, inject) => {
const hello = (msg) => console.log(`Hello ${msg}!`)
// Inject $hello(msg) in Vue, context and store.
inject('hello', hello)
// For Nuxt <= 2.12, also add 👇
context.$hello = hello
}
and then add this file in nuxt.config.js:
export default {
plugins: ['~/plugins/hello.js']
}
Use Nuxt's inject to get the method available everywhere
export default ({ app }, inject) => {
inject('myInjectedFunction', (string) => console.log('That was easy!', string))
}
Make sure you access that function as $myInjectedFunction (note $)
Make sure you added it in nuxt.config.js plugins section
If all else fails, wrap the function in an object and inject object so you'd have something like $myWrapper.myFunction() in your templates - we use objects injected from plugins all over the place and it works (e.g. in v-if in template, so pretty sure it would work from {{ }} too).
for example, our analytics.js plugin looks more less:
import Vue from 'vue';
const analytics = {
setAnalyticsUsersData(store) {...}
...
}
//this is to help Webstorm with autocomplete
Vue.prototype.$analytics = analytics;
export default ({app}, inject) => {
inject('analytics', analytics);
}
Which is then called as $analytics.setAnalyticsUsersData(...)
P.S. Just noticed something. You have your plugin in client mode. If you're running in universal, you have to make sure that this plugin (and the function) is not used anywhere during SSR. If it's in template, it's likely it actually is used during SSR and thus is undefined. Change your plugin to run in both modes as well.
This would be the approach with Vuex and Nuxt:
// store/index.js
export const state = () => ({
globalThing: ''
})
export const mutations = {
setGlobalThing (state, value) {
state.globalThing = value
}
}
// .vue file script
export default {
created() {
this.$store.commit('setGlobalThing', 'hello')
},
};
// .vue file template
{{ this.$store.state.globalThing }}

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 ....
}