Dealing with performance issues in VueJS and Vuetify's data-table component, especially when trying to implement

In my VueJS and Vuetify project, I encountered an issue. I am trying to create a table with expandable rows for displaying orders and their associated products. The table needs to show at least 100 rows of orders on one page. To achieve this, I utilized the <v-data-table> component from Vuetify framework.


The Challenge

Upon completion, I noticed that the expansion of each row was taking too long (which is not acceptable for a fast system). It was also causing significant lag when expanding all visible records, requiring over 20 seconds.


My Attempts

I initially tried using the standard Vuetify <v-data-table> with the show-expand prop and the expanded-item slot - but it was slowest in performance. Then, I attempted to customize it:

<v-data-table>
 <template v-slot:item="{item}">
   <td @click="item.expanded = !item.expanded">expand / hide</td>
   <!--- [my table content here - too long to post it here] -->
   <tr v-if="item.expanded">
     <td :colspan="headers.length">
     <v-data-table>
       <!--- [content of the nested table - also too long to post it here] -->
     </v-data-table>
   </tr>
 </template>
</v-data-table>

An interesting observation - v-if performs faster than v-show, which contradicts the common belief that changing from display: none to nothing should be less taxing than adding/removing objects from the DOM.

This method showed some improvement compared to the initial approach, but it was still sluggish. I also tried setting :ripple="false" for every v-btn in my tables, which helped slightly. I conducted tests on Chrome, Firefox, Windows, Linux Fedora, and Android smartphones.


What more can I do to optimize the performance?

Thank you for your help!

Answer №1

According to a well-written article, the performance impact is highest due to the sheer number of DOM nodes. Despite this, I did not encounter any significant performance issues while testing a sample application created to explore your specific problem. The page containing the table loaded in approximately 1.25 seconds (from localhost), regardless of whether it was under development or in production mode. As per the JavaScript console timer, expanding or collapsing ALL 100 rows simultaneously only took an average of about 0.3s. Ultimately, it seems like achieving the desired optimizations without sacrificing Vuetify's conveniences is feasible.

Recommendations

  1. It might be beneficial to display fewer rows at once (anticipated significant impact)
  2. Evaluate the template design to minimize elements and ensure that only essential data relevant to users is displayed. It is worth questioning the necessity of having a v-data-table nested within another v-data-table.
  3. Optimize the data model by retrieving only the essential data required for table display. As suggested by @Codeply-er, the size and complexity of the data could be contributing to the strain on performance.

Testing Method

For evaluation purposes, I conducted the following steps: Created a straightforward Vue/Vuetify application featuring a VDataTable with 100 expandable rows sourced from the random user API. I utilized this method to tally the DOM nodes. Below are some pertinent details:

  • Rows: 100
  • Columns: 5 + expansion toggler
  • Expansion row content: VSimpleTable displaying user picture and address
  • Size of individual JSON record from API: ~62 lines (approximately half the size of the provided sample object)
  • Vue v2.6.11
  • Vuetify v2.3.0-beta.0
    (Considering the recent release, using v2.2.x may yield similar results)
  • Application built with vue create myapp and vue add vuetify
  • VDataTable dynamically adds/removes expansion rows from the DOM based on user actions

The rough statistics derived from the experiment (subject to minor fluctuations under varied conditions) include:

  • 773 (~7 per row): DOM nodes count in 100 rows/5 columns without expansion enabled
  • 977 (+2 per row): node count with expansion enabled
  • 24: nodes added when expanding a single row
  • 3378 (+26 per row): total nodes when ALL rows are expanded
  • ~1.25s overall page load time upon hard refresh
  • ~0.3s to simultaneously expand or collapse ALL nodes
  • Column sorting utilizing built-in tools proved swift and efficient

Below is a snippet from the App.vue file where the v-data-table serves as a primary component alongside a toggle button, sans external imports:

<template>
  <v-app>
    <v-btn
      color="primary"
      @click="toggleExpansion"
    >
      Toggle Expand All
    </v-btn>
    <v-data-table
      :expanded.sync="expanded"
      :headers="headers"
      :items="items"
      item-key="login.uuid"
      :items-per-page="100"
      show-expand
    >
      <template #item.name="{ value: name }">
        {{ name.first }} {{ name.last }}
      </template>
      <template #expanded-item="{ headers, item: person }">
        <td :colspan="headers.length">
          <v-card
            class="ma-2"
            max-width="500px"
          >
           <!-- Expansion row content here -->
          </v-card>
        </td>
      </template>
    </v-data-table>
  </v-app>
</template>

<script>
  import axios from 'axios'
  export default {
    name: 'App',
   <!-- Other script-related details will go here -->
  }
</script>

To preview a functional demo, visit this codeply link. Hopefully, this information proves useful!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The function $http.get in AngularJS is providing an undefined response

In the process of developing a small Angular application, I started with this seed project: https://github.com/angular/angular-seed. The only modifications I made were to the following files: /app/view1/view1.js 'use strict'; angular.mod ...

Tips for displaying an alert after a successful form submission and ensuring user input validation

I created a form with PHP code to send emails, but I'm struggling to add an alert without page refresh upon submission. The alert needs to display in green or red text below the button. Validation for email input is needed, as well as protection again ...

Using Angular JS, send out a notification and pause execution until it is finished

I recently encountered an interesting situation involving an Angular event: $rootScope.$broadcast("postData"); doSomething(); However, I realized that doSomething() needs to wait for the completion of postData before executing. This led me to contemplate ...

Updates to the AngularJS model are not appearing in the user interface

Despite executing the controller code, the values in the UI remain unchanged. The initial values are displayed without any issue. I've attempted to call $scope.$apply() at the end of each function (submit and transfer), but it didn't resolve the ...

Error encountered during Ajax request - two files being transmitted instead of one

Can someone assist me with a basic ajax call for a login button? I need help with the form submission and sending the request to a php file to handle the login action. However, I am encountering an issue where two files are being sent instead of one when ...

Instantly magnifying on the initial point regardless of the zoom type chosen is a feature of Chart.js zoom

Despite adding zoom functionality to my line chart, I am facing an issue where it automatically zooms in to the first point and does not allow me to zoom back out, except for using the reset zoom function. The zoom out function is also not working properly ...

The data type of Subscription: prototype, NOT ASSIGNED

I am encountering the following error when attempting to return a subscription object. Error Message:-------- Type 'Subscription' does not have the prototype and EMPTY properties that are expected from type 'typeof Subscription' Here ...

What are the steps to successfully implement "Pointermove" event delegation in Safari iOS for parent/child elements?

I've encountered an issue that I'm struggling to find a solution for. My goal is to implement an event delegate using pointermove on a parent container, and I need to be able to detect when the event transitions between a child element and the pa ...

How can I quickly calculate arithmetic operations for every element in a cell array?

Assuming I need to multiply each element in a cell array A by a coefficient k, the typical approach is: A = cellfun(@(x) k*x, A, 'UniformOutput', false) However, this method is quite slow. Is there a more efficient solution? It's worth not ...

Using jQuery to locate and delete multiple attributes from div elements

My goal is to locate all div elements with the class name "comment-like" that also have data-id attributes set to 118603,1234,1234,118601,118597. If a div contains any of these data values, then I want to remove that data attribute. I've attempted th ...

align all items centrally and customize Excel columns based on the length of the data

Is there a way to dynamically adjust the column width based on the length of data in an Excel report using PHPexcel? Additionally, how can I center all the data in the Excel sheet? Here is the current code snippet: <?php if (!isset($_POST['send&a ...

How to dynamically insert li elements into a ul list using the .after() method

After trying to add an li element to the ul list, I noticed that my DOM wasn't updating when checking the page source. Even attempting to delete elements with the delete button didn't seem to work as expected. Here is the code snippet below. ...

Exploring the process of transforming a dynamic PDF into a static PDF using PHP or NodeJS

Issue I am looking for a PHP/NodeJS API that can convert editable PDF files to non-editable PDFs online. Our client application requires the user to download PDF files that cannot be modified using software like Foxit Reader or Adobe. We are currently us ...

Struggling with getting the JavaScript, scss, and CSS television animation to turn on and off properly? Seeking assistance to troubleshoot this

After finding this javascript code on Codepen and seeing that it worked perfectly in the console there, I tried to run it on my computer with jQuery but it didn't work outside of Codepen. Even when attempting to use it on JSfiddle or compile the SCSS ...

When using setTimeout in NodeJS/Express, a TypeError is thrown stating that it cannot read the property 'client' as it is undefined

My nodejs express route is basic: app.get('/timeout', function (req, res) { setTimeout(() => { console.log('timeout'); }, 2000); res.send({ hello: "world" }); }); However, it's not functioning cor ...

Setting a default value in the <v-select> component: A handy guide

After setting up a select component like this: <v-select px-4 class='select' v-model="form.accountType" :items="accountTypes" :label="$t('form.accountType')" :rules="[rules.required, rules.validAccountType]" ...

Is it possible to trigger the eventListener just once for every instance of my constructor?

I have a common property that is shared among all instances of my constructor: function Me() { } Me.prototype.window = {}; I want to update this property when the window is resized, but I only want it to happen once for each resize event, regardless of h ...

Mastering the art of knowing when to implement asynchronous and synchronous programming techniques is essential for

As I explore asynchronous programming in JavaScript, I am faced with the challenge of integrating two email providers: Sendgrid and Mailgun. My goal is to send an email using one provider, and if any errors occur during the process, automatically resend th ...

Tips for organizing information within a table

I have been developing a tool that allows users to enter a username, and then I display the data fetched from GitHub related to that particular user. Although each cell in the table is sortable, they all seem to sort data based on the first cell. When I cl ...

Limited functionality: MVC 5, Ajax, and Jquery script runs once

<script> $(function () { var ajaxSubmit = function () { var $form = $(this); var settings = { data: $(this).serialize(), url: $(this).attr("action"), type: $(this).attr("method") }; ...