Содержание
Все компоненты Razor, с которыми мы работали ранее, наследуются от базового абстрактного класса Component. У этого класса определены методы, благодаря которым мы можем управлять жизненным циклом компонента Razor.
Методы жизненного цикла компонента Razor
У класса Component определены следующие методы жизненного цикла:
OnиInitialized() OnInitialized Async() OnиParameters Set() OnParameters Set Async() OnиAfter Render(bool firstRender) OnAfterRenderAsync(bool firstRender)
при этом синхронные версии методов вызываются перед асинхронными. Рассмотрим эти методы более подробно.
On Initialized() и On Initialized Async()
Методы OnInitialized() и OnInitializedAsync() используются исключительно для инициализации компонента на протяжении всего срока службы экземпляра. Используя эти методы, можно, например, инициализировать значения каких-либо свойств или полей компонента. Если используется синхронная версия метода, то инициализация родительского компонента гарантировано будет завершена раньше, чем дочернего. В случае использования асинхронных версий предугадать какой компонент будет инициализирован первым невозможно, так как очередность инициализации будет зависеть от кода метода инициализации.
Чтобы продемонстрировать вышесказанное, создадим новое приложение Blazor Hybrid и изменим код компонентов Home и Counter следующим образом:
Counter
@page "/counter"
<h1>@message</h1>
<p role="status">Current count: @CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
string message = "";
[Parameter]
public int CurrentCount { get; set; } = 0;
protected override void OnInitialized()
{
message = $"Компонент Counter инициализирован {DateTime.Now:hh:mm:ss:fff}";
}
private void IncrementCount()
{
CurrentCount++;
}
}
Home
@page "/"
<h1>@message</h1>
Welcome to your new app.
<Counter CurrentCount="10"></Counter>
@code{
string message = "";
protected override void OnInitialized()
{
message = $"Компонент Home инициализирован {DateTime.Now:hh:mm:ss:fff}";
}
}
Теперь Counter является дочерним компонентом для Home. У обоих компонентов мы переопределили синхронный метод OnInitialized() в которых выводим точное время выполнения метода. Запустим приложение и посмотрим на результат:
Сколько бы раз мы не перезапускали приложение компонент Counter будет инициализирован всегда позже, чем Home. Теперь попробуем применить асинхронные версии методов следующим образом:
Метод OnInitializedAsync() компонента Counter
protected override async Task OnInitializedAsync()
{
await Task.Delay(Random.Shared.Next(100,1000));
message = $"Компонент Counter инициализирован {DateTime.Now:hh:mm:ss:fff}";
}
Метод OnInitializedAsync() компонента Home
protected override async Task OnInitializedAsync()
{
await Task.Delay(Random.Shared.Next(100,1000));
message = $"Компонент Home инициализирован {DateTime.Now:hh:mm:ss:fff}";
}
Теперь методы OnInitializedAsync() у обоих методов будут «зависать» на случайное количество миллисекунд, поэтому предугадать какой из компонентов будет инициализирован первым становится невозможно. Например, можно получить вот такой результат:
Как видно по рисунку, родительский компонент инициализирован позже дочернего.
OnParametersSet() и OnParametersSetAsync()
Эти методы вызываются после инициализации компонента в OnInitialized() или OnInitializedAsync() и после того, как родительский компонент устанавливает параметры дочернего компонента. Чтобы продемонстрировать очередность выполнения методов, снова изменим компоненты Home и Counter следующим образом:
Counter
@page "/counter"
<ul>
@foreach (string s in message)
{
<li>@s</li>
}
</ul>
<p role="status">Current count: @CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
List<string> message = [];
[Parameter]
public int CurrentCount { get; set; } = 0;
protected override void OnInitialized()
{
message.Add($"Компонент Counter инициализирован {DateTime.Now:hh:mm:ss:fff}");
}
protected override void OnParametersSet()
{
message.Add($"Параметры компонента Counter установлены {DateTime.Now:hh:mm:ss:fff}");
}
private void IncrementCount()
{
CurrentCount++;
}
}
Home
@page "/"
<h3>
<ul>
@foreach (var s in message)
{
<li>@s</li>
}
</ul>
</h3>
Welcome to your new app.
<Counter CurrentCount="10"></Counter>
@code{
List<string> message = [];
protected override void OnInitialized()
{
message.Add($"Компонент Home инициализирован {DateTime.Now:hh:mm:ss:fff}");
}
protected override void OnParametersSet()
{
message.Add($"Параметры компонента Home установлены {DateTime.Now:hh:mm:ss:fff}");
}
}
Так как мы используем синхронные методы, то все методы будут выполняться по порядку — сначала пройдет инициализация Home, затем сработает метод OnParametersSet(), затем инициализируется Counter и ему будут назначены параметры:
On After Render(bool firstRender) и OnAfterRenderAsync(bool firstRender)
Методы OnAfterRender() и OnAfterRenderAsync() вызываются после интерактивной отрисовки компонента и завершения обновления пользовательского интерфейса. В этом методе рекомендуется производить какие-либо дополнительные шаги по инициализации компонента, например, для вызова скриптов JS, которые взаимодействуют с уже отрисованными элементами DOM.
При этом, параметр firstRender устанавливается в значение true при первом рендеринге экземпляра компонента и может быть использован для обеспечения того, чтобы работа по инициализации выполнялась только один раз.
Эти методы вызываются последними. Например, переопределим этот метод в компоненте Counter:
@page "/counter"
<ul>
@foreach (string s in message)
{
<li>@s</li>
}
</ul>
<p role="status">Current count: @CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
List<string> message = [];
[Parameter]
public int CurrentCount { get; set; } = 0;
protected override void OnInitialized()
{
message.Add($"Компонент Counter инициализирован {DateTime.Now:hh:mm:ss:fff}");
}
protected override void OnParametersSet()
{
message.Add($"Параметры компонента Counter установлены {DateTime.Now:hh:mm:ss:fff}");
}
private void IncrementCount()
{
CurrentCount++;
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
message.Add($"Рендеринг компонента Counter завершен {DateTime.Now:hh:mm:ss:fff}");
}
else
{
message.Add($"Повторный рендеринг компонента Counter завершен {DateTime.Now:hh:mm:ss:fff}");
}
}
}
Теперь запустим приложение и посмотрим на результат:
Так как компонент уже был отрисован перед выполнением метода OnAfterRender(), то строка «Рендеринг компонента…» была добавлена в список message, но не была выведена на страницу. Чтобы увидеть время рендеринга компонента можно поступить двумя способами:
1. Заставить компонент перерисоваться, например, нажав кнопку «Click me». Результат будет следующим:
2. Вызвать метод StateHasChanged() базового класса, чтобы заставить компонент перерисоваться, например, так:
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
message.Add($"Рендеринг компонента Counter завершен {DateTime.Now:hh:mm:ss:fff}");
StateHasChanged();
}
else
{
message.Add($"Повторный рендеринг компонента Counter завершен {DateTime.Now:hh:mm:ss:fff}");
}
}
Теперь строки из метода OnAfterRender() будут показываться сразу после рендеринга:
Метод StateHasChanged() стоит использовать с осторожностью, чтобы не получить бесконечный рендеринг компонента. Например, вот так делать НЕ надо:
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
message.Add($"Рендеринг компонента Counter завершен {DateTime.Now:hh:mm:ss:fff}");
}
else
{
message.Add($"Повторный рендеринг компонента Counter завершен {DateTime.Now:hh:mm:ss:fff}");
}
StateHasChanged(); //получаем бесконечный рендеринг
}
Результат будет вот таким:
Итого
Компоненты Razor имеют четко определенный жизненный цикл, воздействовать на который мы можем переопределением методов жизненного цикла. Порядок выполнение методов от инициализации компонента до его удаления из интерфейса следующий: OnInitialized() —> OnParametersSet() —> OnAfterRender(firstRender = true) —> OnAfterRender(firstRender = false) —> ….. OnAfterRender(firstRender = false).






