You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Destroying N RouterLink at once has a cost of O((N^2)/2) due to all RouterLink depend on the singleton reactive property $route. When removing hundreds or thousands of links from the page, this cost is noticeable, especially on slow devices. The goal is a cost of O(N).
Hundreds or thousands of links might seem too much, but sure there might be some cases where it makes sense, like an infinite scroll or some big grids. In many cases vue-virtual-scroller should solve the general problem, but I think it would be better not to require it as a rule.
Removing the dependency on $route means effectively disabling reactivity for the RouterLink and thus all the related features. At this moment, I think the only affected features are the CSS classes to show a link is active.
Why this cost?
The singleton _route is created for the _routerRoot once. At this moment, Vue instantiates a Dep to track writes and reads on this attribute.
Each time a RouterLink is created, its render Watcher detects the $route is accessed, so that the Watcher adds the Dep to its dependencies (Watcher.deps) and the Dep adds the Watcher to its subscribers (Dep.subs). This means the Dep.subs for _route is, at least, as large as the number of rendered RouterLinks.
When the $route changes, all the RouterLink are updated because they are on the Dep.subs.
When destroying all the RouterLink (page change), all the components teardown their watchers, and each watcher have to remove itself from the Dep.subs. Removing a single RouterLink's Watcher from the Dep.subs costs O(N - i), where N is the number of RouterLink and i the number of RouterLink already removed.
Generally speaking, the cost of removing N RouterLinks at once is O((N^2)/2).
What does the proposed API look like?
Adding a no-reactive prop on RouterLink should be enough.
The meaning of this prop is effectively disabling reactivity on the current route to improve the overall performance, especially when destroying many RouterLink at once.
As a side effect, this flag turns off any feature that depends on the current route. At this moment, I think the only affected features are related to the CSS classes to show if a link is active or not.
Unfortunately, as noted at #3500 (comment), the change needed would be to use Sets() instead of Arrays. The reason Vue 2 doesn't use them is to support IE without polyfills. That's also why Vue 3 doesn't have that limitation. In other words, if you want to fix this you will have to:
Not support IE
Create a local patch to use Set instead of arrays within vuejs/core
This can't be fixed in router's code unless a new component is added but this won't happen for an edge case that isn't an issue in newer versions anymore. So even if someone gets the fix done, it won't get released, probably blocking them from getting the bounty. Instead, the person can contact you to get paid for the feature as a patch with https://www.npmjs.com/package/patch-package without us getting involved in such a transaction.
BTW Vue 2.7 is backwards compatible with Vue 2.6, so you should be able to upgrade. Any other bug fixes will happen in 2.7 not in 2.6
What problem does this feature solve?
Destroying N RouterLink at once has a cost of O((N^2)/2) due to all RouterLink depend on the singleton reactive property $route. When removing hundreds or thousands of links from the page, this cost is noticeable, especially on slow devices. The goal is a cost of O(N).
Hundreds or thousands of links might seem too much, but sure there might be some cases where it makes sense, like an infinite scroll or some big grids. In many cases vue-virtual-scroller should solve the general problem, but I think it would be better not to require it as a rule.
Removing the dependency on $route means effectively disabling reactivity for the RouterLink and thus all the related features. At this moment, I think the only affected features are the CSS classes to show a link is active.
Why this cost?
The singleton _route is created for the _routerRoot once. At this moment, Vue instantiates a Dep to track writes and reads on this attribute.
Each time a RouterLink is created, its render Watcher detects the $route is accessed, so that the Watcher adds the Dep to its dependencies (Watcher.deps) and the Dep adds the Watcher to its subscribers (Dep.subs). This means the Dep.subs for _route is, at least, as large as the number of rendered RouterLinks.
When the $route changes, all the RouterLink are updated because they are on the Dep.subs.
When destroying all the RouterLink (page change), all the components teardown their watchers, and each watcher have to remove itself from the Dep.subs. Removing a single RouterLink's Watcher from the Dep.subs costs O(N - i), where N is the number of RouterLink and i the number of RouterLink already removed.
Generally speaking, the cost of removing N RouterLinks at once is O((N^2)/2).
What does the proposed API look like?
Adding a no-reactive prop on RouterLink should be enough.
The meaning of this prop is effectively disabling reactivity on the current route to improve the overall performance, especially when destroying many RouterLink at once.
As a side effect, this flag turns off any feature that depends on the current route. At this moment, I think the only affected features are related to the CSS classes to show if a link is active or not.
ORIGINAL LINK: #3500 (comment)
The text was updated successfully, but these errors were encountered: