primefaces / primevue

Next Generation Vue UI Component Library
https://primevue.org
MIT License
9.89k stars 1.19k forks source link

Tree: Performance is bad when you have a large number of children #6196

Open Ancient-Dragon opened 1 month ago

Ancient-Dragon commented 1 month ago

Describe the bug

When you start to load more then 100/200 children into a tree, then the performance opening the tree is really bad, the page just hangs.

I'm pretty sure this can be easily resolved by just adding the virtual scrolling component to the tree where it renders the children.

Here is a demo: https://stackblitz.com/edit/wcrnhu just try and open the documents tree

Reproducer

https://stackblitz.com/edit/wcrnhu

PrimeVue version

4.0.4

Vue version

4.x

Language

TypeScript

Build / Runtime

Vite

Browser(s)

No response

Steps to reproduce the behavior

Open the documents tree and wait for it to eventually load

Expected behavior

Open the documents tree and have it open instantly when there are more than 1000 objects in the data set.

Ancient-Dragon commented 1 month ago

Tagging @tugcekucukoglu please can you look into this? (I would try but seems master is broken for primevue as I can't run the dev server locally)

snakemastr commented 1 month ago

+1

We have the same issue and also wanted to use the filtering which is also painfully slow.

In my opinion a Tree should be able to handle a lot of data. Sadly I see more issues for components that do not work well with heavy datasets but are expected to like DataTable and TreeSelect. Could they be related?

Is the problem rendering nodes or executing some heavy method for each node?

ZiadJ commented 1 month ago

Have you considered using a DataTable for displaying the rows and only use the Tree to navigate the hierarchy?

Ancient-Dragon commented 1 month ago

Nope, a DataTable isn't what we're after since we just have a single field to display.

ZiadJ commented 1 month ago

Well, you can always use a single list instead, wrapped within a virtual scroller. The problem otherwise is that, with multiple lists under each parent node with their own scrollbars it might be a bit difficult to navigate, don't you think? And if you're going to push the height to the max so as to remove the scrollbars then there'd be no point in using the virtual scroller anyway, taking us back to square one. Else what do you suggest?

ZiadJ commented 1 month ago

Here's the code used to iterate with children btw. It's a plain iterator and I'm not sure how to further optimize it:

<ul v-if="hasChildren && expanded" :class="cx('nodeChildren')" role="group" v-bind="ptm('nodeChildren')">
    <TreeNode
        v-for="childNode of node.children"
        :key="childNode.key"
        :node="childNode"
        :templates="templates"
        :level="level + 1"
        :loadingMode="loadingMode"
        :expandedKeys="expandedKeys"
        @node-toggle="onChildNodeToggle"
        @node-click="onChildNodeClick"
        :selectionMode="selectionMode"
        :selectionKeys="selectionKeys"
        @checkbox-change="propagateUp"
        :unstyled="unstyled"
        :pt="pt"
    />
</ul>

Anyway, the upcoming Vue 3.5 will come with significant performance gains out of the box so, hopefully, that'll fix it out of the box.

Ancient-Dragon commented 1 month ago

Yeah I mean this is what I had:

                        <VirtualScroller :items="node.children" showLoader :itemSize="17" :numToleratedItems="20" style="height: 200px">
                            <template #item="{ item }">
                                <TreeNode
                                    :key="item.key"
                                    :node="item"
                                    :templates="templates"
                                    :level="level + 1"
                                    :loadingMode="loadingMode"
                                    :expandedKeys="expandedKeys"
                                    @node-toggle="onChildNodeToggle"
                                    @node-click="onChildNodeClick"
                                    :selectionMode="selectionMode"
                                    :selectionKeys="selectionKeys"
                                    @checkbox-change="propagateUp"
                                    :unstyled="unstyled"
                                    :pt="pt"
                                />
                            </template>
                        </VirtualScroller>

But as you say, it creates a scrollbar for every group which is slightly annoying. But I feel like there could still be some optimisation done by utilising the concept of a virtual scroller, i.e. knowing what is visible and only rendering those items.

Our use case is that we have it in a dialog so it don't just fill the entire page up, it's confined to a space and there's a scrollbar.

agersant commented 1 month ago

Related: https://github.com/primefaces/primevue/issues/5396

Profiling shows that a huge amount of time is being spent (wasted?) in setAllNodeTabIndexes when adding a large amount of children to a TreeNode.

Ancient-Dragon commented 1 month ago

Tagging @tugcekucukoglu again to see if we can get this worked on?