Performance impact of stacking multiple Vue components - vue.js

I am building an application that uses Vue to display most of the data that my users will see (charts, tables, etc.)
Now, imagine I have a table built with Vue with a list of actions performed by each user. Now, the user name cell will be especially formatted with the user’s picture, social handle, etc. The way the user is presented in this table is the same as it will be in other components. It will also contain some especific functionality (e.g. hovering over the picture will provide expanded information about the user; but this functionality is only planned).
My objective is to reuse as much code as possible. This is why I was planning to have a small UserProfile.vue component inside my Table.vue component. Using this logic, I may repeat this for other information as well (think CompanyProfile.vue, ProjectDetail.vue, etc.).
Is this a good idea? Will it have cause significant performance issues to have multiple vue components inside one and other?

Vue has optimized the result of rendered html as far as possible. You don't need to worry a lot about it. Child components only update when their respective data has changed, that is usually quite cheap.
Good to keep in mind:
When authoring components, it’s good to keep in mind whether you intend to reuse it somewhere else later. It’s OK for one-off components to be tightly coupled, but reusable components should define a clean public interface and make no assumptions about the context it’s used in.
For larger applications, you may use Async Components
Vue will only trigger the factory function when the component actually needs to be rendered and will cache the result for future re-renders. For example:
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// Pass the component definition to the resolve callback
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
I found some interesting topics that you might want to look:
Performance for large number of components
Performance degradation when using components
Unlock performance tracing in vue
Analyze runtime performance
So now, you know what to do. Hope, it helps.

Related

Vue component with input provided by a function vs reactivity

I understand that reactivity is a big deal in VueJs. However, I tend to use OOP for my front end development, and therefore data is often provided by functions. This will be naturally non-reactive, which can be overcome by using this.$forceUpdate.
The question is - is this a fundamentally bad concept? Or is it just fine? Is there a better way? Probably watchers can be used, but I feel like that would make the code more complicated.
Example:
<template>
<multiselect
:value="myclass.getValue('param1)" />
#input="val => valueUpdated(val)"
</template>
Then in methods:
valueUpdated(newVal)
{
this.myClass.setValue(newVal);
this.$forceUpdate();
}
Note, myClass has async data, so by the time of the first rendering, it is not filled with the data. MyClass comes into the component as a prop, and it is a TypeScript class.
this solution works fine, but is there a better (correct) way?
Doing/forcing view to update manually is a fundamentally bad concept. The view should update at the moment your data changes - and it should update automatically. This is what reactivity gives you. This is like going from a car with manual gears and 49 shifts to a car with automatic shifting.
The whole idea is that you define declaratively the behavior of your view - how it depends on the data model. Building the view imperatively is more tedious and error-prone and certainly less elegant.
OOP may work well in non-visual libraries - but for UI composing components with props and events works better.

Are vuex mapGetters even worth using?

So I believe the title introduces my question. Given you're introducing a new dependency in each component you want to use mapGetters in, this adds bloat to your package.
This also means your component is now specifically bound to Vue, which is 1 more thing to contend with were you to port components over to another framework like React.
Consider these 2 computed property lists:
import { mapGetters} from 'vuex'
computed: {
...mapGetters({
active:'interface/active',
mode:'interface/mode',
views:'interface/views',
}),
}
vs
computed: {
active:() { return this.$store.getters['interface/active'],
mode:{ return this.$store.getters['interface/mode']},
views:{ return this.$store.getters['interface/views']},
}
Sure the latter is a tad bit more verbose, but nothing overly bad. You've still got all your getter data the same way in either scenario. To be this seems like totally unnecessary fluff for the small benefit of saving a few characters.
The former example weighs in at 207B (201 characters)
while the later example weights in at 207B (201 characters).
To me that means in terms of type savings, there's virtually none to be had. However I do concede that the former is more readable, portable and ultimately easier to maintain as your relevant data is all in 1 spot.
There are a couple of things that I think are worth mentioning here, regarding an opinion you have on the helper function like mapGetters
About your code being tightly coupled to vuex should you decide to import mapGetters: it should be clarified that the approach where you access this.$store.getters directly doesn't make your code any less coupled to vuex. After all, such direct access already does assume quite a lot about store's functionalities and how they're exposed to components.
Take snippets you provided as examples, it can already be seen that your store implementation a) has a concept called getters, and that b) it supports modules such that you can define an interface module like you did.
Suppose one day, you somehow decide to switch store's implementation to something like puex, which has absolutely no concept of either getters or modules, you will have to refactor all 3 declarations anyway. Or even if you decide to switch to something more advanced like Flure, it will also put you in a similar situation: though Flure has concepts of getters and modules, they aren't exposed the same way vuex does, so you have to edit all 3 lines (again).
Let alone porting to React, the code you have in computed properties won't even be portable to other store libraries created specifically for Vue. So, really, you shouldn't worry too much about using mapGetters.
Secondly, for type-saving sake, if you're not going to rename these properties anyway, your mapGetters call can actually be shortened to a one-liner:
computed: {
...mapGetters('interface', ['active', 'mode', 'views']),
}
Third, once you start having multiple lines of these, it's just easier to track all declarations (e.g., how many getters or state fields you expose from each module). So these helper functions actually helps improve maintainability if used well.
computed: {
...mapState('interface', ['list', 'packages']),
...mapGetters('interface', ['active', 'mode', 'views']),
...mapGetters('foo', ['bar', 'baz']),
}
Forth, regarding bundle size, on second thought I believe this might be the main reason why people downvoted you. So, I'll try to explain:
The thing you need to understand is that real-world production webapps these days use build tools like webpack to create javascript bundles. And because of that, javascript you wrote can be pretty much regarded as source code, which is totally different from the code shipped in a bundle. The reason why they are so different is that the bundle can utilize both minify and gzip techniques to achieve drastic improvement in file size (usually more than 70% size reduction in practice).
In other words, for webapps these days, javascript is not being served as-is, but almost always be processed by webpack or the like. So, all the character counting you have been doing on the source code isn't going to make a noticeable difference to the final bundle size at all. And because of this, some people might regard your concern as an extremely bad form of micro-optimization, hence their downvotes.
If I were you, I will try to embrace these helper functions as much as possible, and look at the bundle size after automatic build optimizations before worrying about the bundle size at all. And even if the final bundle size is too big to your liking, I can almost guarantee you won't gain much from mapGetters refactoring, as it's usually other stuff that substantially bloats the bundle size (like a view component library, for example). Really, premature optimization on vuex isn't really worth your trouble.
So, to me, these functions (mapState, mapGetters, mapActions, mapMutations) are definitely worth using.

In Mobx can a complex component have it's own store?

I have built a complex date management component that itself is made up of many smaller components nested a few layers deep. The components at different levels need access to observables and actions that live in the root component. I am dealing with this by passing what I need through props. While this all works, the code would be much simpler and easier to follow if I could create a store in the root component, use provider, and then inject in the child components as needed. Exactly like we do when creating a store for app wide use.
So to summarize...
I want each instance of my complex date component to create it's own instance of a store. I want to then use provider and inject to pass this store instance to child components.
Before I proceed with this significant refactoring, I want to be sure that this approach will work and is sound. Is there an alternative approach that makes more sense. Am I overlooking something?
Note: Although I know code samples are useful, I'm hoping that what I am describing is straight forward enough that they are not needed in this case.
Yes, you can create stores for a component and use Provider and inject to pass them to child components. Actually that is what I do in my current project and it works well.
BTW, I think this is a big Pro of MobX compared to Redux. You do not need to keep all states in a single global store. You can create complicated components that work perfectly by themselves. It is object-oriented, which is the philosophy of React.

vue.js how to organize front-end data (e.g. product information)

What is the correct pattern to store e.g. static product information data within a vue2 single page application?
Previously I've used an external js file that included a JSON with product-attributed (e.g. name, weight, height etc).
I don't want to load via AJAX since the spa needs to work without a web-server.
While VueX is meant to provide to a single source of truth for dynamic data throughout your single page application, I think it's also the proper and clean way of storing static data. VueX allows you to write getters and setters (as mutations / actions), now if you simply leave those setters out of your module you'll have a centralized store module that is read-only but available in every component.
Why is that better than just using a static JSON file?
Using a JSON file will expose the entire content to every single component that uses that file. In some cases that might be what you want, but it's by far not as flexible as having multiple getters that allows you to define the exact scope of what each component should receive. Also VueX uses all observable patterns and best practices from Vue itself, so the integration of your data in for example computed properties is super easy. Due to the getters pattern you'll also be able to define any kind of filtering or sorting in one place that you can share in your entire application. While that might not be what you need right now, keep in mind your requirements may change over time and simply having the option to easily implement that later is also a good thing. Same goes for reading the data from an Endpoint instead of having it statically. Your application might not need that right now, but in case you want to do that somewhen in the future, vuex will make it super easy to transition to dynamic data without you having to change any component.
What speaks against VueX?
Not that much. While it's a little bit of overhead if you really only use it for static data, the possible scalability it offers you is worth that minor downside.

Difference between calling new Vue() from main.js V/s calling from each and every component

I have a project where I have initialized new Vue() from main.js using #app.mounted.
Thereafter I have injected all router views from each and every component into the app.
Now, what I am thinking is I should call new Vue() in each and every component instead of calling from one central main.js file.
I am asking if this approach of calling/importing Vue and initializing from each and every file is a good approach or should I stick to initialize from one central file.
It is perfectly valid to include multiple Vue instances, there is nothing wrong with that, as long as they are self-contained and and didn’t rely on other Vue instances. It’s still fine to access Vue instances after they have been initialized, because this doesn’t break the principle of loose coupling, and they can therefore still be isolated from each other.
Adding two Vue instances to the same page, which operate on different parts of the DOM. This is very useful for adding widgets to a page, eg, one Vue instance would be responsible for a form on the right hand side of the page, and another would control the navigation.
But, as it's not a big problem at a small scale, it can quickly lead to code that is very hard to maintain. Because your Vue instances would no longer be isolated from each other, it can be very hard to figure out the dependencies between them, and changing something in one Vue instance could easily break another.I just want to recommend that you stay away from this approach.
Single Vue instance bound to the whole page and do all of your logic in one component, that can get messy very fast. It all depends on what you're trying to achieve, but vuex can help keep your state in order while using multiple components.
No. There is no need to generate a new Vue instance.
Generally speaking, only single Vue instance should exist in your application.
Special Use cases that might lead you to create multiple Vue instances:
Event Bus: It requires a new Vue instance.
Mounting Vue instances on different parts of your legacy DOM. You never need this if you create Vue application from scratch.
I highly recommend you to take a look at high-quality solutions (templates) that are already made up for you and maintained by a large community, before taking decisions that has already been addressed.