Vuex Module Initialization Best Practice - vue.js

(updated with additional background)
I have a Vuex store module that needs to load its data at the beginning of time, automatically, so it's available when requested (in this case it's a 'settings' store that loads data from electron-settings at startup, but there are lots of reasons why I might need something like this).
Right now I'm achieving this by setting up a special 'init' action on my store module and dispatching it from my Main.vue component on the 'mounted' lifecycle hook, like this:
mounted() {
this.$store.dispatch('initSettings');
}
What I was hoping for is a way the module could simply initialize itself. Ideally, something like a lifecycle hook akin to the 'mounted' hook on my component, but triggered within the vuex store module. This way users of my module would not need to know they must call 'init' as well as instantiating it.
I've searched through the docs and haven't come across a solution for this, but in case I'm just searching for the wrong thing, I was hoping someone out there has found an elegant way to do this.

If your store is in a separate file store/index.js, you can just import it.
import store from '/store';
store.dispatch("stuff")
This is because ES6 imports are references and bind to the runtime data structure. The following import store from '/store' statements will get the same reference as the first.
require() makes copies. It's a notable difference.

i needed something similar and my solution is to run is when the document is loaded:
var app_store = new Vuex.Store({
state: state,
getters: getters,
mutations: mutations,
actions: actions,
});
$(document).ready(function()
{
app_store.dispatch("initSettings",null);
});

Related

How can I remove manually added event listeners on beforeDestory hook of one component before redirecting to any another component, in Vuejs2?

I want to know the concept of the below thing-
I have created one component and set up its respected event listeners. Now, I want to remove those listeners on this component's beforeDestroy hook before redirecting to another route that will create another component.
but what I noticed is, beforeDestory hook of the first component is calling even after the second component's created hook.
I want to destroy the first component completely and then create another component.
// To set up the event listeners
created() {
this.EventBus.$on('myCustomEvent', payload => {
// some code here
)}
}
// To destroy the event listeners
beforeDestroy() {
this.EventBus.$off('myCustomEvent');
}
Any suggestions?
In search of an answer to your question, I came to the conclusion that it is better to refuse to use EventBus altogether.
Here is some information on this and some thoughts from there:
I have that feeling that having an EventBus in Vue is an anti-pattern, especially if you’re using VueX but I can’t quite put my finger on it. At the point you want to be sharing data like that, wouldn’t it be better to use a store to handle all of those “events” / “mutations”?
Also, looking at the solution to this issue, you are doing everything right and there is no other way.

Nuxt (SSR/Vuex): Dispatch an action once all of the components have been created

Consider the following Widget component.
<template>
<component :is="name" />
</template>
<script>
import { mapActions } from 'vuex';
export default {
props: {
name: {
type: String,
required: true
}
},
created() {
this.addWidget(this.name);
},
methods: {
...mapActions({
addWidget: 'widgets/add'
}) // adds widget name to an array
}
};
</script>
I want to have multiple components like this one all over the page.
I need to be able to gather all of the component names so I can fetch the relevant data for them.
My current idea is to add the component name to the store when the created hook fires.
That works just fine, but my problem is that I can't find a way to dispatch a Vuex action to fetch the data once all of the components have been created. I tried using various hooks to no avail since none of them seems to have Vuex access.
Am I missing something? Is there some kind of hook that fires after all of the components have been created (SSR) that has Vuex access. Or maybe there's some better way to achieve what I've been trying to do?
Why do you want to wait until all the widgets have been loaded to fetch the data? Instead, what I'd do is fetch the data for each Component as they get added in the page. Using this approach, each component would require a specific piece of data, and nothing better than to load each of them in a different request. Easier to test, easier to trace, adheres to the single responsibility principle.
If you are worried that two components may require the same data, then you can route all requests through an Object that hashes the request (endpoint + verb if using REST) and keeps a pool of active connections, so that if two requests come in one reuses the Promise of the other, and only one of them reaches the server.
Now, if you really want to do it using your original approach, make it so that each widget emits an event once it's been registered. The events are collected by the parent component (maybe the Page that loads all the widgets). The page knows which Widgets are being loaded. Every time an event is received it sets a flag on that specific widget to indicate it's been loaded. Once all widgets get a flag, the Page triggers a request to fetch the data.

Global vuex watchers

I have a Vuex store feeding many Vue components in a somewhat large web app. I would like to be able to watch Vuex states or getters for logging purposes. However, I want to be able to watch them 'globally', i.e. without relying on any particular Vue component. This rules out tricks like
//aComponent.vue
watch:{ '$store.state.data'(value, oldValue) { /*do something here*/ }}
and
//App.vue
created() {
this.$store.watch((state) => state.watchedState) => {/*do something here*/ })
}
Instead, I am looking for a way to watch my Vuex states or getters directly from the module where the store is defined, so that whenever a state changes, I can call a function passing it as arguments the old state and the new state, so as to write the change into a database (ideally the change itself would be detected automatically, as in Vue's watch(new,old) {...}.
I suppose I should use Vuex native method store.watch() for this purpose. But so far I have not be able to invoke it from the store module, as desired.
Any clue? Or did I miss something and what I am trying to do would be just as efficiently done with a different technique?
For watching mutations you have this options.
You can subscribe to a store and get notified by mutation after it happens.
store.subscribe( (mutation, state) => {
})
You can achieve this in a couple of ways:
use subscribe on the store you create by hand, most likely in main.js
create a plugin that gets appended to each instance of a store and again subscribe to it
just use the vuex official plugin for logging
For watching getters you probably need to monkey patch the getters property by hand.
Then again, if you want to watch what happens with vuex during development you can use vuejs tools

How To Ensure Reference Data Is Loaded In Vue?

I have webpack setup to bundle all of the source. I have a Vue object that is the page and multiple Vue components of my own creation. This works great!
I am now getting reference data from the database to fill in certain default options for some of these components. In my pages Mounted or Created events (there is no difference for my question) I am calling a method that will check to see if the data exists in localStorage and if not, it will extract the data from the database.
Once Extracted, I have it in localStorage so it is not an issue. However, the first time I need to gather the data (or when I need to refresh it because I have another trigger that lets me know when it has changed) the page and components have rendered (with errors because of lack of data) before the data comes back. The fetch method is in a promise, but mounted events don't seem to care if a promise exists within in before it continues to the next component.
So what is the best practice for loading/refreshing reference data in Vue? I am currently not using VueX because this is not a SPA. Sure, it is a single page that is doing things (there are many single pages that do their own thing in this site) but I have no need to make it a full SPA here. But If VueX and its store will give me some sort of guarantee that it will occur first or page/components will run AFTER VueX things, I will learn it.
Have you tried doing so:
<component v-if="page.isDataLoaded">...</component>
in your Vue-component:
data() {
return {
page: {
isDataLoaded: false,
}
}
},
mounted() {
this.fetchPageData().then(() => this.page.isDataLoaded = true);
}
You can use v-if and v-else to show, for example page loader element like so:
<PageLoader v-if="!page.isDataLoaded"></PageLoader>
<component v-else>...</component>

Custom business objects in vue

I am new to vue and have a few questions around using a simple business object in my vue single page components. Let's stay I have an object called ResultCalculator. This is a simple javascript class that contains my core business logic for calculating something. Now assume I want to use this object in my Home.vue component. My questions are:
1) Is it best practice to simply create a new file called ResultCalculator.js and
export default class ResultCalculator {...}
2) In order to import this into Home.vue I use the import ResultCalculator from '....ResultCalculator.js'
3) In my create method, I simply new up a new object and assign it to this.resultCalculator.
The above is working for me, but is it best practice?
4) Now I'd like to reference some data in vuex state store. I doesn't seem like I simply use this.$store.getter. How do I reference vuex in this component?
Thanks
Sure, just create a js file and import it to your .vue files there is nothing wrong with that.
You can not use this.$store because in ResultCalculator.js this is not vue. You can either pass this.$store as an argument or just simply import your store to ResultCalculator.js