javascriptdomblazorblazor-webassembly

How to notify blazor(webassembly) about DOM changes made from js?


I'm trying to reduce render count of a very heavy component which renders thousands of spans. I can't apply virtualization because spans have different size.

<div contenteditable="true">
    @foreach (var item in els)
    {
        <span @key="@item.Key" class="@item.cssClass">@item.String</span>
    }
</div>

I made an attempt to replace span by a component which renders span and it works, but initial render time was taking too long.

I can't do everything via js and disable rerender because root div may contain some other blazor components.

I need to apply some changes via JS without rerender, but at some time rerender happens and render state is corrupted. How can I notify blazor about changes in dom? Or maybe I need to revert all changes made from js before render?

Change types:

  1. modify span's textContent
  2. split span at some offset
  3. add span into div

Do I need to use something like node.dispatchEvent(new Event('change'))? Are there any possible problems here?


Solution

  • Blazor does not provide a built-in mechanism to notify the .NET runtime about DOM changes made by JavaScript, or to synchronize arbitrary JS changes with the Blazor app state. The framework is not designed for this and such practices are generally not recommended.

    What you can do is call a C# .NET method with JSInterop after doing the JavaScript changes. Provide information about the changes to the .NET runtime and then for each of the possible change types do the following, is applicable:

    1. Modify <span> content: find the correct item in the els collection and change its String property value.
    2. Split <span> at some offset: replace the corresponding item in the els collection with two new items with the correct String values.
    3. Add <span> to <div>: add a new item to els.

    When doing the server-side changes, you can override the ShouldRender() method of your component and temporarily disable re-rendering, because the DOM in the browser is already up-to-date.

    Update: Note that it may not be always possible to achieve perfect synchronization between the server-side app state with the DOM state. For example, Blazor uses empty HTML comments <!-- --> to distinguish components and their parts. The JavaScript DOM changes may break this mechanism. If this occurs, the only option is to remove the whole <div> with all <span>s temporarily with server-side code and re-render everything from scratch.