Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
The ChangeDetection
class will shortcut rerendering when it knows a Parameter
value is an immutable type and the oldValue
is equal to the newValue
.
This is a request to be able to identify complex types (classes / structs) as immutable, so the ChangeDetection
class can also skip rerendering if the type of the Parameter
value is marked as immutable and the oldValue
is the same reference as newValue
.
Scenario
- Page has a
List<Order>
- Page uses a grid component to render those rows
- Grid uses a component to render each row
- User clicks a button, edits a value, or performs any event that will cause the Page to rerender
- The parameter to the Grid is a reference type, so the grid will rerender
- Each
Order
in the list is a reference type, so each row in the grid will rerender
This problem becomes much more pronounced as we componentise a complicated page, having child components passing state to their own children etc, or have grids that have sub-grids (e.g. a grid of Order
objects, where you can expand any row and see the OrderLine
objects for that Order
).
In many cases this is desirable, however, in cases where each row is an immutable object there is no need to rerender the row components at all.
Problem
In cases where the data is a view model only so will not change, this causes lots of unnecessary rerendering.
Describe the solution you'd like
Request
Change the Blazor ChangeDetection
class so that if
- The
oldValue
of the parameter is the same reference as thenewValue
for the parameter, - and
newValue.GetType()
is decorated as[Immutable]
, - then assume the value is unchanged and therefore does not need to cause a rerender.
Common alternative suggestions
Override ShouldRender
This isn't a suitable solution because there are often times when developers are using 3rd party components, on which we cannot override this method.
We also don't want to override ShouldRender in the page, as we might want the page to rerender (e.g. changing a Date on an Order, but not changing any of the Lines that are presented in a grid).
Considerations
Non-breaking change
This should be a non-breaking change as it is up to the developer to specifically add [Immutable]
to the models. If they do not wish to use this functionality, they do not need to add that attribute.
Ability to disable
In cases where the developer is unable to alter the data-model classes that do use this attribute (i.e. third party API) and they are experiencing a problem due to a 3rd party component vendor not yet accounting for this behaviour, then we could have a feature flag in Blazor that the ChangeDetection
class checks. The developer can then disable this default behaviour and Blazor will act exactly as it already does.
No reliance on Blazor assembly
A clean architecture approach would mean not having references to UI assemblies such as Blazor from an API data-models (contracts) assembly. Therefore this [Immutable]
attribute should be added to System.DataAnnotations
.
It would not ensure the object is immutable, it would just be a hint to consumers of the class.
Conclusion
- A non-breaking change that requires little work
- that is possible to disable
- that requires no work on the part of Blazor developers
- that will work with components for which Blazor developers have no access to the source code
- introduces a standard way of identifying immutability (and therefore no need to rerender) rather than expecting component venders to come up with their own solutions.
Additional context
References to similar requests / complaints on social media about rendering
https://www.reddit.com/r/Blazor/comments/sx8raj/prevent_bindvalue_rerendering_entire_page
https://www.reddit.com/r/Blazor/comments/ugi9qd/why_is_blazors_rendering_so_inefficient/
#38984
#13610
#40867
#21915
#26016