Я использую последнюю версию Blazor WebAssembly 3.2.0 Release Candidate
Из ванильного шаблона Blazor WASM я внес следующие изменения для тестирования / отладки проблемы:
В Program.cs Я добавляю следующий синглтон, который будет вставлен на все страницы:
builder.Services.AddSingleton<ApplicationState>();
Класс выглядит так:
public class ApplicationState
{
public bool BoolValue { get; set; }
public string StringValue { get; set; }
public ApplicationState()
{
BoolValue = false;
StringValue = "Default value";
}
}
и введен в _Imports.razor вместе с JSRuntime, поэтому они доступны для всех страниц:
@inject IJSRuntime JSRuntime
@inject BlazorApp1.State.ApplicationState AppState;
Чтобы проверить правильность прохождения объекта ApplicationState через приложение, я использовал его в следующие 2 места:
В NavManu.razor Я оборачиваю один из пунктов меню вокруг BoolValue , чтобы показать / скрыть этот элемент:
@if (AppState.BoolValue)
{
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
}
И в Index.razor я добавил тег H2 под заголовком Hello World по умолчанию, чтобы отобразить StringValue
<h1>Hello, world!</h1>
<h2>@AppState.StringValue</h2>
У меня также есть javascript файл, расположенный в wwwroot/js/extenstions.js, он имеет единственную функцию, используемую для приготовления пищи * 1 086 * data:
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
};
И включен как скрипт в wwwroot/index.html прямо под _framework / blazor.webassembly. js скриптом:
<script src="_framework/blazor.webassembly.js"></script>
<script src="js/extensions.js"></script>
В App.razor У меня есть следующий @ code блок:
@code
{
protected override async Task OnInitializedAsync()
{
AppState.BoolValue = true;
AppState.StringValue = "Testing 123...";
}
}
Все работает как положено и пункт меню отображается так же, как и строковое значение в теге H2.
Однако, если я добавлю вызов моей функции Javasript через JSRuntime, например:
@code
{
protected override async Task OnInitializedAsync()
{
var jwtToken = await JSRuntime.InvokeAsync<string>("getCookie", "cookieName");
AppState.BoolValue = true;
AppState.StringValue = "Testing 123...";
}
}
Запускается javascript, и значения AppState обновляются (я добавил журнал консоли, чтобы проверить это) НО навигация не обновляется, чтобы показать элемент меню, а тег H2 не показывает новое строковое значение ...
Если вы перейдете на страницу в меню, состояние обновится, но этого не произойдет снова, если вы выполните жесткое обновление sh ....
Я попытался добавить StateHasChanged ( ) вызов, но это не сработало:
@code
{
protected override async Task OnInitializedAsync()
{
var jwtToken = await JSRuntime.InvokeAsync<string>("getCookie", "cookieName");
AppState.BoolValue = true;
AppState.StringValue = "Testing 123...";
StateHasChanged(); // Does not work!
}
}
Поскольку состояние, казалось, обновлялось после навигации, я также попытался принудительно запустить канун навигации nt, тоже безрезультатно:
@code
{
protected override async Task OnInitializedAsync()
{
var jwtToken = await JSRuntime.InvokeAsync<string>("getCookie", "cookieName");
AppState.BoolValue = true;
AppState.StringValue = "Testing 123...";
var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
NavigationManager.NavigateTo(uri);
}
}
Я продолжаю пробовать еще несколько вещей, но, похоже, ничего не работает. StateHasChanged () действительно должно было быть исправлением для чего-то вроде этого в моем понимании. Что-нибудь еще, что я должен попробовать?
UPDATE
Как указано в enet, мне нужно уведомить нижестоящие компоненты, когда состояние изменилось. Проблема была вызвана не JSRuntime, а задержкой, которую он создал в App.razor, в результате чего состояние объекта при аппаратном обновлении sh казалось другим. В первом сценарии объект был обновлен ДО того, как другие компоненты начали рендеринг, поэтому они использовали уже обновленное состояние. Но как только возникала какая-либо задержка (например, вызов JSRuntime), им требовалось уведомление, чтобы обновить свое состояние, потому что у них была возможность выполнить рендеринг до задержки с использованием более старого состояния. Я заменил вызов JSRuntime на Task.Delay () на несколько миллисекунд, и это привело к той же проблеме! Это разрешило добавление триггера к событию.