Vue 3 disable caching of components - previous components are now being stacked - vue.js

I am developing a Vue3 application with a component that renders a D3 chart.
The problem occurs when I navigate to another page and get back to the same D3 component but with different data. The D3 charts keep on getting stacked on each other.
I am using Vue3 and found it is a bit difficult to disable caching of components but perhaps I missed some options. I wouldn't mind disabling caching completely, because most of the data is obtained from localStorage, so pretty quick anyway
Here is a sandbox to illustrate the problem:
https://codesandbox.io/s/vue-3-vuex-4-vue-router-forked-eem3ui?file=/src/components/Miserables.vue
If you click on the "Miserables" link, then to another link (Playerlist or About) and back to Miserables, you'll see the charts stacked.

You have at least 2 "smells" in your code:
you are creating and injecting <script> tags every time your Miserables component is being mounted - after multiple mountings you will have a lot of duplicate JavaScript code, pontentially poluting the global namespace (multiple times) and worse - potentially attaching multiple event handlers or setting up timers;
on every mounting you are creating a new SVG and appending it to the BODY - so it's not Vue's fault that you're getting multiple SVGs on the page;

Related

Vue 3: how to sequentially add an element one after another?

My problem is the following:
I need to render a bunch of Tableau graphs on a page.
I am currently calling them in tableau-graphs component as follows:
TableauGraphs Component
<template>
...
<tableau-graph
v-if="urls.length > 0"
v-for="(chartUrl, index) in urls"
:src="getVizUrl(chartUrl, ticketList[index])"
/>
...
</template>
When I do this, all the charts are called immediately one after another, and tableau decides the order in which they are loaded. This behaviour is undesired because there might be many graphs and tableau can decide to load a graph much further down on the screen before the first one.
I want to try to do the following:
make tableau-graph component emit a ready event once its loaded.
the parent tableau-graphs listen to that event and load the next chart in urls.
repeat 1-2 until there are no more charts to load.
I have gotten the child component to emit a custom event and listen to it. However, I have not been able to programmatically add a new component in the template. I have tried using h function but I am unsure how to mix it with a regular template syntax.
So, my questions are:
How do I programmatically add an existing Vue component to another in script setup?
Is this a desirable way to go about solving this issue, or is there more elegant way to solve this problem? (For example, using Async Components and/or Suspense)

How to improve performance while using dynamic components in vue?

Context:
Currently, I am working on a complex editor application which uses vuex state, vuetify's expansion panel and vue's dynamic component. Each dynamic component uses data which is accepted as props and has its own nested components.
Problem:
The issue with this approach is as the app deals with the large, nested state, the add operation in the UI slows down and makes the UI unusable.
Note:
In the example, I have added 1000 objects just to replicate the issue. Unfortunately cannot use pagination here.
Is there any other way to approach this problem to improve the performance, any suggestions would be helpful.
Issue:
Codesandbox - Demo
Codesandbox - Edit
You are using index as your key and at the same time adding new item to the beginning of the array using unshift - which means every time the new item is added, all components needs to be rerendered. Use :key="item.name" instead and you will see huge speed improvement on adding new items...
Initial render is another problem - if the pagination is not an option, you can look at some virtual list solutions which do render only part of the list visible and make scrolling effective by reusing existing components. One example is vue-virtual-scroller. Vuetify itself has it's own implementation but I'm not sure how well it will work with expansion panel considering this note in the documentation:
We are in the process of integrating the v-virtual-scroll component into existing features and components. If you are interested in helping, please reach out to John Leider in the Discord Community.
(Also it seems you are using really old version of Vuetify...)

VueJs: Two Independant & Seperate Routes/Views with vue-router

The Goal: Have two separate, independently navigateable routes with vue-router.
Details:
How can I have two parts of a page that are independently routed with vue router? Say you have a page split into a main view and a sidebar. The main view is what you would normally expect from a view, you click on links and it changes the path and loads a new component. The sidebar is completely separate, no matter where you are in the main view the sidebar does not change, but the sidebar also has links that let you go to different components within itself.
With vue-router, I can have named views, but these seem to be tied to whatever the current path/route is, and cannot be controlled separately.
Example Annotation:
Question
Can vue-router have two separate, and independent routes/views that are not tied to each other? If so, is there documentation on this, are there router code examples?
Note: There is no code here, it doesn't seem necessary as this isn't a code issue, it's a vue-router use-case issue.
You can achieve separate independent routes if you use 2 Vue apps each with its own router.
A small demo in this fiddle.
I've used 2 routes, one with history mode and one abstract.
The biggest problem I see with this is that, at least out of the box, you cannot have a URL that points the user to the same view(s), as now you are managing 2 different routers.
The other is related to communication, you now have 2 different Vue app instances so you need to do something about communication between them.
But this shouldn't be that hard
if you are using Vuex you can set the same store object on both of them
If you are just using a plain data object you can pass the same object to both instances and that will become reactive or
you can always communicate over the same bus

Binding some Vue code to existing, server-side generated HTML

I have an old-style, multiple-page website, with a multiple steps checkout process. This all works with JS disabled, and it is critical that it keeps doing so.
The checkout form has no JS at all, at the moment, and I'd like to improve it progressively (eg. dynamically showing or hiding fields, doing live validation, etc...).
I have already wrapped the entire website with an #app div, and I mounted a Vue instance to it. Then I created a few components which work correctly (but are not critical, so if JS is disabled then the whole thing keeps working and the components are just empty).
Now I have a long checkout form which is generated server-side (say: <form id='address-form'>).
The best course would be to put it into a component (say <checkout-form>) and use it. I can't do this, because 1) the form is generated server-side 2) it needs to work without JS.
Ideally, I would love to create a component with no template, and attach it to the existing HTML.
Is this even possible?
Edit: continuing to dig the Internet, I found this tutorial. This is exactly my problem, but if this is the only way to do it, then I will revert to JQuery :) Manually duplicating the entire HTML (one server side, the other in Vue) is definitely not a good idea.

Should I use code splitting on every component in vue?

I have an application in vue with typescript. I saw when I use import to load component then I got component-bundle with all the code of component inside.
I wonder if should I do this for every component I want to load, for example: I have app.vue inside I have toolbar.vue and drawer.vue. in my router components I have others vue components.
What I'm afraid that gonna happened is app.js is loaded then components inside the route definition(500k), then I get the toolbar component (1.5mb). and I'll get flashing screen weird.
So, should I use splitting bundle for every component in my app?
You can do code splitting if you are not expecting that particular component to be re-used for every page.
Take for example the Header and Footer component. Since they will be used in almost all of the pages, there is no reason to code split as you want it to be loaded along with the bundle for all pages.
Take for example you have a component where it has a Blog Widget. This component will only load in the /blog page. Therefore, this is a good use case to be using code splitting as you do not need the Blog Widget to be bundled in other pages except in the /blog page.
I can only provide you with a generic answer and using the Header and Footer components are the best way to express different use cases. As for the rest of the components, you have to decide for yourself if it is worth to code split or not.