Vuetify performance issues - javascript

I have picked vuetify for an offline PWA project where I work with indexed DB and some notable size data (5k-6k/collection). I have to transfer it between vuex and IDB after I get them from the server.
Reading and saving them is kinda slow (200-300 ms), and freezing the UI for a short time. I thought making a full-screen loading screen while it was loading helped, but it still make the loader stutter.
Also, I have some problems when I am navigating between pages. Loading v-lists (with infinity loading) and swiper (swiper slider) freeze the UI and it feels a little bit off. Especially, when I am adding vibrating to the buttons. The freezing delays the vibration for 100-200 ms and I don't know I am touched the button or not.
Things I've tried so far:
Looping through the list elements, and freezing the objects at vuex mutations (I want to keep the reactivity for array methods). It feels faster, however cloning arrays can delay the initial loading. And still not satisfying.
Using requestAnimationFrame solves the freezing at navigation, but delays the rendering of childcomponents. Also doesn't seem like the best solution.
Using less dom elements. I'am using infinity scrolls for v-lists. It still loads slow despite it only rendering 15 rows. I cannot use a virtual list, because the list elements have different heights. I didn't find a carousel/swiper with
proper virtualization. Vue-awesome-swiper is the most popular, but it loads incredibly slow.
My app
Sadly I cannot share the project here, But I don't use any extraordinary code, that's why I am confused about the low performance.
At service workflow
Getting data as JSON from the server -> vuex action -> committing mutation and saving data to IDB with Dexie's bulkPut -> mutation freezes the objects and saves to the state
At visualization
components using mapgetters to get the lists from vuex. Using these getters, I am making computed properties to filter/reorder data (these methods run under 30ms, so they shouldn't make issues).
I couldn't find any helpful information on how to make my application faster. Even scrolling down the list seems slowy/laggy. I could use webworker to handle IDB at initial loading, but the UI animations would still be slow. Should I use less v-container/v-layout/v-flex etc... and adding native elements to my app? Currently, I am using only vuetify elements.
As I am loading all my data at starting, I am expecting a slower initial loading time for sure, but smooth navigating and fast loading after that.

My site is entirely on Laravel and Vuetify technology. Just a few recommendations. First, there must be a very fast server. Not average in terms of speed, but a fast one. Secondly, the page should not have full-page Vue components. They are first mounted, then displayed. The user sees this as a display after some delay. Further, there should be no data loading via the API after the layout is displayed (the getData method in the mounted hook). And, of course, loading a large amount of data via prop {{json_encode($data)}} delays and degrades performance.

We've built an application with vue/vuetify, where the main component is a complex multidimensional grid generated on the fly.
Our first iteration was painfully slow, once, with meaningful data, we got a rendering time of 9 sec ...
The solution to our problem was two fold:
use functional components wherever possible,
use Object.freeze on data that doesn't need to be reactive (as mentioned) - at this link an explanation of the optimization technique
Now rendering the same component takes fractions of a second.
From the doc:
Functional components are an alternative form of component that don't
have any state of their own. They act like pure functions: props in,
vnodes out. They are rendered without creating a component instance
(i.e. no this), and without the usual component lifecycle hooks.
as always, just my 2c :)

Related

How exactly is React's Virtual DOM faster?

I understand that there are two arguments for React's Virtual DOM being faster -
It updates ONLY those elements that actually need to be updated (using diff).
It batches the updates and hence we update the real DOM only a single time. Thus the repainting is also done only once which otherwise would have been done multiple times.
I have questions regarding both these points -
As far as I know, all the modern browsers are efficient enough to update only the required elements in the DOM. For example, if I have two 'p' tags and I change the text in one of the p tags using a button click, then only that p tag will be updated by safari (I have verified this using paint flashing). So how is point 1 an advantage if it is already being implemented by the browsers?
How exactly does React batch the updates? Eventually React will also have to use the DOM api to update the real DOM. So why is that if we directly use the DOM api then the changes will not be batched whereas when React uses it then they are batched?
I have found the answer to my question.
The key is to understand the purpose of the Virtual DOM.
First we have to see what approach React takes to render the components.
Different javascript frameworks take different approaches to detect changes in the data model and render them on the view.
Consider AngularJS. When we refer to our data in an Angular template, for example in an expression like {{foo.x}}, Angular not only renders that data but also creates a watcher for that particular value. Whenever anything happens in our app (click event, HTTP response, timeout), all the watchers are run. If the value in a watcher has changed then that value is re-rendered in the UI. By running all the watchers AngularJS is essentially finding out where it needs to make the changes. The process of running these watchers is called dirty checking.
React takes a different approach. Whenever there is a state change in a React component, instead of finding out where to make the changes (like AngularJS), React re-renders the entire UI from scratch (with the updated state).
But this approach of React has a problem. To re-render the entire UI means to re-render the entire DOM tree. This is a problem because DOM updation is a slow process (due to reflow and repainting).
This is where React's Virtual DOM comes in. A Virtual DOM is just a representation of the Real DOM in form of javascript objects. It is just a tree data structure of plain javascript objects that exists in the memory. As compared to the Real DOM, rendering of the Virtual DOM is much faster because it is never rendered on the screen (no reflow or repainting needs to be done).
So how does the Virtual DOM solve the problem? When we load our app, React creates a Virtual DOM that is an exact virtual copy of the Real DOM. Whenever there is a state change in a component, instead of re-rendering the entire Real DOM, React renders an entire new Virtual DOM (with the updated state). Then it does a diff between the old Virtual DOM (the initial copy of the Real DOM) and this new Virtual DOM (rendered after state change) to find out the changes between them and it does ONLY those changes in the Real DOM. In this way, the entire UI is re-rendered (by rendering an entire new Virtual DOM) but only the minimum required changes are done in the Real DOM.
So when it is said that "Using Virtual DOM React updates only those elements that need to be updated" (point 1 in my question), it means that with the help of Virtual DOM React is overcoming the limitations of its own approach (approach of rendering the entire UI from scratch).
This answer also explains the same concept.
I have seen some answers that state that DOM manipulation using React is faster than using the DOM api because the DOM api re-renders the entire DOM tree whereas React re-renders only those parts of the DOM tree that need to be changed. This is NOT true. All modern browsers are efficient enough to update only those parts of the DOM tree that need to be changed. This can be verified using paint flashing in developer tools of browsers (also see this answer and this answer). Even if we assume that the DOM api does re-render the entire DOM tree, still this reasoning is false because the internal code of React itself has to use the DOM api to update the DOM. If the DOM api did re-render the entire DOM tree then React would also re-render the entire DOM tree because eventually it also uses the DOM api to update the DOM.
As for the second point, React actually makes batching easier for us.
In React, while the reads are done on the Real DOM, the writes (state changes) are not done on the Real DOM. Instead the writes are queued. Then when all our reads and writes have been processed, a new Virtual DOM is built based on the writes. Then diffing is done between the old and new Virtual DOM and then React writes the required changes to the Real DOM to update it. Hence eventually all the writes on the Real DOM are done together in a single reflow.
But we can manually also, without React, write our code in such a way that first all reads are done and then all writes are done. React makes batching easier because with React we don't have to care about doing the reads and writes together and React will automatically batch the writes for us. So React does not make things fast. It makes things easier.
In conclusion we can say that React is not actually faster. It is easier. As Pete Hunt says in this video, "React is not magic. Just like you can drop into assembler with C and beat the C compiler, you can drop into raw DOM operations and DOM API calls and beat React if you wanted to. However, using C or Java or JavaScript is an order of magnitude performance improvement because you don't have to worry...about the specifics of the platform. With React you can build applications without even thinking about performance and the default state is fast.".
This post by Rich Harris also states that it is a myth that "the Virtual DOM is fast".
Once React knows which virtual DOM objects have changed, then React updates only those objects, in the real DOM. This makes the performance far better when compared to manipulating the real DOM directly. This makes React standout as a high performance JavaScript library.
Regarding the Batch Update:
React follows a batch update mechanism to update the real DOM. Hence, leading to increased performance. This means that updates to the real DOM are sent in batches, instead of sending updates for every single change in state.
The repainting of the UI is the most expensive part, and React efficiently ensures that the real DOM receives only batched updates to repaint the UI.

React.js: Can certain components be made SSR-rendering only?

Coming from some classic server-side template languages (php, jsp), I have a general architectural question on React.js:
Can I limit certain components of a page to be rendered server-side only? And reduce the client-side javascript bundle accordingly?
*I find that often ridiculously large. One reason (afaik): Every component must have the capability to be re-rendered on state changes and SPA-(aka soft, virtual..) page navigation, since all changes come in as data, not as prerendered html chunks (afaik).
Basically, I see 2 different types of content sections in almost all of my web projects:
1) highly dynamic “facebook-ish” interactive sections
Personal greetings, messages and message counters, likes and replies… here default React behavior is at its best: new data comes in, global state (redux store) changes and all affected components get re-rendered. Which would be a daunting task without react and redux sound principles. And certainly client-side rendering/updates are the way to go.
That's often the user-login area at top ("Hello Joe, 5 unread messages"), some live data (stock, weather,…) in the middle and said comments closer to the bottom.
2) SSR “static” content (think PHP)
However, for many sections I know for sure, nothing is client-side dynamic. Footer Menus for example, might stem from a database, but are certain to not change for the duration of the session. (Even if John Doe decides to like, comment or change his name…)
Rendering them only server-side would be enough. Often the main content block can also do with SSR-only. (And all the layout-ish sub-components needed to render its html)
Still, I have to give all components to the client bundle, so that also virtual/soft page navigation works... (which transmits new data, but not pre-rendered sections)
You could tell me as a workaround to simply keep the footer out of the react container mounting point, but that's not my point... "static" aka sections that can do with pure SSR might be elsewhere, too, between dynamic header and lower response/feedback/liking sections…
I would like to mark Type-2-components as "SSR-is-enough" (and also their sub-components – unless webpack dependency tree figures out, they are used in Type1-CSR-components, too…).
So send it as a single html blob. Also receiving it "pre-rendered" on SPA-ish virtual page navigation would be needed afaik. (since the component knowledge will be missing from the client bundle)
Is there a way to do this? Has someone thought of this general, imho common problem before...?
Hydrating only certain components is definitely a problem that is being thought about.
One web framework that solves is problem is Astro. It only hydrates components which are actually interactive.
Another is Fresh, which has a concept called "islands." The entire page is server-side generated and when you need interactivity, you create an "island" which is a component which is hydrated on the client.

How can I improve the performance of passing around a large JSON object in React Native?

I'm building an app with React Native and on my transitions, where I'm loading more data, it's very slow and I'm wondering if there's a better way to structure my app to avoid these shutdowns, which get longer as the JSON file gets larger.
Let's say I have
var data = require('./data/data.json')
in my index view, I think pass this data to a view, which then splits it up to other views like items={data[section_name]} and it goes down recursively like that further down the hierarchy. Creating smaller dicts on each level. And even with small objects it is still quite slow.
The JSON files I'm working with are from 3-8 MBs.
I understand what you want do to with your big data in your project, because I did the same way before for my react-native app.
Actually, this way is fine, it's kind of loading the data once only, then we can retrieve hierarchy easily like items={data[section_name]}
However, the problem now is it may take a while for processing the big data!
Therefore, the idea is we should move the part of loading/initializing the data asynchronously, move it somewhere out of our view, so that the view's transition as well as its other things will not be affected! Then, when the data are being loaded/processed, we may show something like fade-in, fade-out effects, on the view, so it will take a short-time (300-1000ms). However, in my opinion, there may be a better way for this: when the application is opened for the first time, when the splash screen is being shown (for a few seconds, this behavior is common, we can load the big data in the background here!)
FYI, my application loads big data using ajax, it will even take longer than loading local files, but using my above-mentioned way, nobody complains about the data-loading speed ^^ (actually, users don't know and don't see where and when data are loaded, when the app goes to its home/top page, everything has been fully loaded)
Now it comes to the important part of my answer: I suggest you using Flux/Redux for this, maybe Flux is easier for you now, because Redux is kind of an improvement based on Flux (in either Flux or Redux, we will have a Store, and this Store will work asynchronously, you can store your big JSON data here):
https://www.atlassian.com/blog/software-teams/flux-architecture-step-by-step
Flux can be applied on reactjs and react-native of course, you may find there are several new definitions if you don't know about Flux or Redux yet, however, it's really worth reading and trying! After you understand it, it'll be very easy and then you can apply that architecture on whatever react project you like ^^

Preventing UI flicker when loading async data in React.js

I have some data in IndexedDB, which can only be accessed asynchronously. I want to build a React.js UI using that data. The general idea is that I'll have multiple React components that load data from IndexedDB and display some UI based on that data, and the user will be able to switch between which component is currently displayed.
My concern is that I don't know how to elegantly accomplish this without some superfluous UI flickering. I can do my asynchronous data loading in componentDidMount and put the data in this.state, but then render will be called before it's finished, forcing me to either display nothing or display some placeholder data for a tiny fraction of a second while the data from IndexedDB is retrieved.
I'd rather have it not render until after my data from IndexedDB is loaded. I know it won't take long to load, and I'd rather the previous component continue to display while the new data loads, so there is just one flicker (old -> new) rather than two (old -> blank/placeholder -> new). This is more like how a normal web page works. When you click a link from one website to another, your browser doesn't instantly show a blank/placeholder screen while it waits for the server from the linked website to respond.
I'm thinking I could do my data loading outside of the React component before calling React.render and then passing it in via this.props. But that seems messy, because nesting components would become tricky and some of my components will be updating over time and pulling new data from IndexedDB, through the exact same code that initializes them. So it seems like an ideal use case for storing data in this.state because then I could update it within the component itself when I get a signal that new data is available. Initialization and updating would be as easy as calling a this.loadData() function that sets some values in this.state... but then I have the aforementioned extra flicker.
Does anyone have any better ideas? What's the canonical solution to this problem? Is it really to just have millisecond blank/placeholder flickers all over the place?
From the comments it sounds like the behavior you have in the previous implementation (waiting to navigate until you have fetched the necessary data) is the desired goal. If that's the case, the best way to do this without having the flickering would be to use some external object to manage the state and pass the data as props when it has been fetched.
React Router has a pretty good solution where it has the willTransitionTo hook to fetch data for a given component before navigating. This has the added benefit of allowing you to easily catch errors if something goes wrong.
Updated with new link:
https://github.com/reactjs/react-router

React.js app using up a lot of memory ( almost double the original implementation )

I recently ported a heavy page to React. I've kept the html almost identical. The main difference being that, earlier, the server rendered html was directly given to the browser and now, the react rewrite pulls json via a server side API and uses React to manage the DOM.
I've seen heap snapshots for the earlier implementation going up to 55 MBs. For the same data, the heap snapshot for the React.js implementation comes to around 100+ MBs(almost double)
I understand that the json data held in memory will contribute to some increase in the memory consumed. But, when I examined the heap snapshot, I see that around 60% of the retained size is due to some objects whose retaining path contain deleteAllListeners > .... > unmountComponentAtNode . I am trying to understand what that means in terms of reducing the memory used.
Also, could the "data-reactid" attributes added by React to the DOM contribute to a non-negligible increase in memory consumption ?
This question has some more details that might help.
React is using something called Virtual DOM. Basically it constructs alternative DOM tree in memory, in addition to the existing browser DOM tree, but to perform efficient updates it has to keep last displayed Virtual DOM tree in memory, so it can generate fast and efficient updates to the browser DOM tree.
From details of second question, I understand that you have an infinite scroll, where you basically add new components (without removing new ones) when user scrolls down the page. So this should be the source of increased memory usage (since now you have data + virtual dom in memory, compared to the previous solution)
The way it fix it is to render only components which are actually visible to the user, you can try to use react-list, or implement your own component for this.

Categories