Шаблон рендеринга Blazor Server в отношении родительских и дочерних компонентов - PullRequest
0 голосов
/ 04 марта 2020

Я пытаюсь создать список журналов, который перезапускается каждый раз, когда пользователь нажимает кнопку run. У меня есть родительский и дочерний компоненты, родительский объект содержит переменную List, которая передается Child в качестве параметра. Кнопка RUN остается у родителя и запускает службу, которая будет работать.

Я заметил странный шаблон рендеринга. Если я инициализирую List в родительской переменной до запуска сервиса, на экране ничего не отображается, если я удаляю инициализацию, все работает нормально, но список продолжает расти, поскольку он не очищается.

Вероятно, я не совсем понимаю, как работает рендеринг свойств и StateHasChanged, и я был бы очень признателен, если бы кто-нибудь смог пролить свет на это для меня.

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

Сначала создайте проект Blazor Server, обычный шаблон.

Добавить это в NavMenu.razor

<li class="nav-item px-3">
    <NavLink class="nav-link" href="list">
        <span class="oi oi-list-rich" aria-hidden="true"></span> List demo
    </NavLink>
</li>

Создать два класса, Messenger и Сервис

public class Service
{
    Messenger _messenger;
    public Service(Messenger messenger)
    {
        _messenger = messenger;
    }

    public async Task Run()
    {
        await _messenger.AddMessage("test 1");
        await _messenger.AddMessage("test 2");
    }
}

public class Messenger
{
    public string Message { get; set; }

    public Func<Task> OnMessageAdded { get; set; }

    public async Task AddMessage(string message)
    {
        Message = message;
        await OnMessageAdded?.Invoke();
    }
}

Добавить это в методе ConfigureServices класса Startup.cs

services.AddSingleton<Messenger>();
services.AddSingleton<Service>();

компонент Parent.razor

@page "/list"

@using BlazorApp4.Data

@inject Service service

<h3>List of stuff</h3>

<button @onclick="Run">RUN</button>
<Component Messages="messages"></Component>

@code {
    List<string> messages = new List<string>();

    protected async Task Run()
    {
        messages = new List<string>();

        await service.Run();
    }
}

компонент Component.razor

@using BlazorApp4.Data
@inject Messenger messenger

<ul>
    @foreach (var item in Messages)
    {
        <li>@item</li>
    }
</ul>

@code {
    [Parameter]
    public List<string> Messages { get; set; }

    protected override void OnInitialized()
    {
        messenger.OnMessageAdded += OnMessageAdded;
    }

    public async Task OnMessageAdded()
    {
        await InvokeAsync(() =>
        {
            Messages.Add(messenger.Message);
            Console.WriteLine(messenger.Message);
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        messenger.OnMessageAdded -= OnMessageAdded;
    }
}

Итак, если вы go до Parent.razor и закомментируете строку //messages = new List<string>();, программа будет работать просто отлично, кроме того, что каждый раз не очищать список нажата кнопка RUN .

Забавно, если вы не закомментируете эту строку инициализации сообщений и добавите await Task.Delay(1); в первую строку Run ( ) метод класса Service , все отлично работает.

Что мне здесь не хватает?

...