OnAfterRenderAsync
and OnAfterRender are called after a component has finished rendering.
OnInitializedAsync
and OnInitialized are invoked when the component is initialized after
having received its initial parameters from its parent component in
SetParametersAsync.
Moving your code to the OnInitializedAsync method will load the user data before the control has rendered.
Edit: (you want to pass state between components)
Microsoft documentation on State Management
Another example of keeping state in memory and passing it to components via Dependency Injection.
To make use of 'State management' you have to register a 'Service' that can be used for state management.
For example; Create a class named AppState with the values you would like to keep state of.
public class AppState
{
public AppState()
{
//this class is to help maintain application state.
}
public UserData UserData { get; set; }
public string SomeOtherStateValue { get; set; }
}
then register this class in your Services as Singleton (see Service Lifetimes):
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
//...other services
//...
// add AppState as singleton
builder.Services.AddSingleton<AppState>();
//...
//...more stuff
await builder.Build().RunAsync();
}
Then in your Index.razor file (or wherever you need to call it for the first time) use dependency injection to get access to the AppState and in the OnInitialzedAsync() call the user data using HttpContent.
@page "/"
@using System.Text.Json
@using System.Text
@inject AppState appState
@inject HttpClient httpClient
<h1>..all your html or components on the page...</h1>
@code{
protected override async Task OnInitializedAsync()
{
var userRequestData = new UserDataRequest(options);
var request = new StringContent(JsonSerializer.Serialize(userRequestData), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync($"api/users/", request);
if (response.IsSuccessStatusCode)
{
appState.UserData = await JsonSerializer.DeserializeAsync<UserData>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
await base.OnInitializedAsync();
}
}
This will await the call to the API until it has received a response.
If the response was successful ie: response.IsSuccessStatusCode is true. extract the data from the response message and store it in the appState.UserDate.
In any subsequent component you can get the AppState by injecting it using @inject AppState appState or if it is in a code file [Inject] AppState appState;
In the subsequent components you can add a check in the OnInitializedAsync method :
.
.
if (appState?.UserData == null)
{
//appData.UserData = await request user data...
}
// more code..
.
.
!! This is not how authentication should be handled though !!
If you need authentication look at ASP.NET Core Blazor authentication and authorization as it makes use of AuthenticationStateProvider.
In regards to checking if the call has already been made to the http client, the await should wait for the response from the httpClient before continuing.
If appState.UserData has some value then the call was successfull..