chanan / BlazorStyled

CSS in Blazor Components
https://blazorstyled.io
The Unlicense
191 stars 19 forks source link

Rerendering of component with multiple classes #107

Open esso23 opened 4 years ago

esso23 commented 4 years ago

Let's say we have a component called <MasterComponent>. This component has style definitions within declared using <Styled @bind-Classname>.

When the component has a single css class defined in it, the component's OnAfterRender method is called twice, which is standard. Also the <Styled> component's OnAfterRender is called twice. This is fine.

When you have 2 css classes, each class gets rendered 3 times and <MasterComponent> OnAfterRender method is called 3 times aswell.

When you have 20 css classes, each class gets rendered 21 times (for a total of 420 renders) and the <MasterComponent>'s OnAfterRender is called 21 times too.

When I create a <ChildComponent> with 20 css classes and I render it 10 times in <MasterComponent> and I also render <MasterComponent> 10 times, I get 46200 calls to OnAfterRender on <Styled> components. That's a lot. This problem could get really bad in larger applications where you can get to millions pretty easily.

I think this is a big contributor to the performance problems in v3 mentioned here https://github.com/chanan/BlazorStyled/issues/104

To be completely honest, I have no idea why it happens. Maybe you'll understand it better.

chanan commented 4 years ago

I agree that is the issue as well. I think the same problem should occur in v2 (and 1) as well.

I did my best to make the impact smaller. The first thing BlazorStyled does is get a hash of the string and stops if it saw that hash before. But even this takes time (and allocations).

I am not sure there is any way to “fix” this (I put fix in quotes because this is an expected behavior of Blazor.

I think, although I might be wrong, that if the css was a parameter instead of child content then I would get for free the non rerender functionality (or implement should render)

But it would look ugly...

<Styled css="color:red" @bind-classname="@myClass" />

Looks fine in the small example above, but obviously, it would be problematic for huge strings of CSS.