Компоненты Blazor: данные исчезают и загружаются снова через 4 секунды.

Это компонент меню, который находится в MainLayout. Теги H5 появляются и исчезают в мгновение ока, а затем через 4 секунды. Он снова загружается. Кто-нибудь встречает такую ​​же проблему?

<ul class="nav-title">
    <li class="brands">
        <div class="menu-dropdown sb-2">
          @foreach (var brand in Brands)
          {
            <div class="nav-column">
                <h5>@brand.Header</h5>
                <ul>
                  @foreach (var item in brand.Items)
                  {
                    <li>@item.Id</li>
                  }
                </ul>
            </div>
          }
       </div>
    </li>
</ul>
@code {
    private List<BrandModel> Brands { get; set; } = new List<BrandModel>();

    private List<CategoryModel> Categories { get; set; } = new List<CategoryModel>();

    private List<ColorModel> Colors { get; set; } = new List<ColorModel>();

    protected override async Task OnInitializedAsync()
    {
        Brands = await HeaderNavComponentService.GetBrandAsync();
        Categories = await HeaderNavComponentService.GetCategoryAsync();
        Colors = await HeaderNavComponentService.GetColorAsync();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JS.InvokeVoidAsync("lazyLoadNav");
        }
    }
}

Обновите ответ @enet:

render-mode = "Server" отключает мигание, и задержка остается.

Я действительно хочу загружать данные как можно быстрее. Скорость предварительного рендера - это именно та, которую я хочу. В этом мигании он также получает значение, полученное из службы. Мне просто не нравится та часть, которая исчезает и загружается обратно по прошествии времени, когда ни одна строка кода не сообщает приложению о таком поведении.

Поскольку эта проблема возникает, я предполагаю, что любые динамические компоненты будут иметь минимальное мертвое время (2 секунды + время загрузки данных) из-за отсутствия данных.

Это действительно грустный UX, хотя приходится ждать некоторое время, чтобы иметь возможность посмотреть список навигации. Похоже, мой план использовать Blazor для нового проекта нарушен :(

Обновление ответа Хенка:

На самом деле для меня не имеет смысла ставить StateHasChange () после каждой присвоенной переменной, что могло бы помочь, но это помогло. Но все еще мерцает.

Затем я меняю render-mode = "Server", и результатом является ожидаемое поведение, при котором больше не будет мерцания, данные быстро привязываются к пользовательскому интерфейсу.

Итак, я думаю, что бы вы ни делали, OnInitialize будет запускаться дважды, просто он не будет привязываться к пользовательскому интерфейсу на этапе предварительного рендеринга, если режим рендеринга помещен на сервер.


person Phuc Vuong    schedule 21.01.2020    source источник


Ответы (2)


Это странное поведение и может быть ошибкой. Мне удалось воспроизвести это с помощью простого кода ниже:

@page "/"

<p>Hello world</p>

@if (strings != null)
{
   @foreach (var str in strings)
   {
      <p>@str</p>
 }
}
@code{

   public List<string> strings { get; set; } = null;

   protected override async Task OnInitializedAsync()
   {

       await Task.Delay(4000);

       strings = new List<string>() { "Apple", "Orange", "Banana" };
   }

}

Насколько я понимаю, код должен работать так:

  1. Метод OnInitializedAsync начинает выполнение

  2. Обнаружение ожидаемого вызова метода (await Task.Delay(4000);), результатом которого является передача управления вызывающему коду.

  3. Blazor начинает рендеринг или вывод пользовательского интерфейса. Первый рендеринг разметки Html <p>Hello world</p>

  4. А потом взял перерыв из-за @if (strings != null), но Blazor беззастенчиво игнорирует мою команду, входит в цикл и начинает рендеринг тегов p со значениями, которые еще не получены ... имейте в виду, они должны быть получены только через 4 секунды.

  5. Сразу после рендеринга тегов p со значениями из массива строк Blazor повторно визуализирует еще раз, на этот раз только <p>Hello world</p>, ждет 4 секунды, а затем повторно визуализирует еще раз, на этот раз <p>Hello world</p> плюс теги p со значениями из массив строк

Действительно, очень странно ... Ой, подождите ... Я понял проблему ... Такое поведение является результатом установки атрибута режима рендеринга компонента Tag Helper на "ServerPrerendered". Сделайте это, и это поведение исчезнет.

<app>
    <component type="typeof(App)" render-mode="Server" />
 </app>  

Надеюсь это поможет...

person enet    schedule 21.01.2020
comment
Моя теория заключается в том, что компонент был уничтожен и снова инициализирован, и во второй раз он делает что-то, что занимает около 2-3 секунд, а затем, наконец, получает данные. Как бы объяснить, почему теги h5 уже показывают данные, полученные из службы, а затем исчезли. - person Phuc Vuong; 21.01.2020
comment
Он вызывается дважды, потому что вместо одного рендера используется два, он согласован. Здесь не происходит никакого волшебства. Сервер выполняет предварительную визуализацию приложения (через то, что мы называем статическим предварительным модулем предварительной визуализации, а затем разрывает его. Затем клиентское приложение загружается и снова визуализирует исходное приложение (следовательно, 2 визуализирует 2 вызова). В случае предварительной визуализации + повторного подключения (исходная сторона сервера Пример) мы откладываем вызов onafterrender до тех пор, пока не установим соединение с сервером, чтобы обеспечить работу, аналогичную тому, что происходит в случае без предварительной визуализации. - person enet; 21.01.2020
comment
Источник вышеуказанного: github.com/dotnet/aspnetcore/issues/ - person enet; 21.01.2020
comment
Вы пробовали использовать HTML-тег компонента так, как я показал в своем ответе? Это помогло решить вашу проблему? - person enet; 21.01.2020
comment
Я обновил свой вопрос. render-mode = Сервер обрезает первый рендер, но все же второй рендеринг занимает слишком много времени для извлечения данных. - person Phuc Vuong; 21.01.2020
comment
Я только что узнал, что способ избежать двойного рендеринга - это кешировать состояние на этапе предварительного рендеринга. Завтра проверю и обновлю результат. - person Phuc Vuong; 21.01.2020

Иногда вам нужно помочь:

protected override async Task OnInitializedAsync()
{
    Brands = await HeaderNavComponentService.GetBrandAsync();
    StateHasChanged();
    Categories = await HeaderNavComponentService.GetCategoryAsync();
    StateHasChanged();
    Colors = await HeaderNavComponentService.GetColorAsync();
}

и эти методы Get ___ Async () должны быть действительно асинхронными.

person Henk Holterman    schedule 21.01.2020