Blazor form submit needs two clicks to refresh view

隐身守侯 提交于 2020-03-23 07:27:12

问题


I have the following Blazor component I'm testing an API call to get weather data. The submit button needs to be clicked twice for some reason in order for the table to display the updated object's properties.

When the page initializes I get the location from the browser just fine and the weather data is displayed in the table without issue.

FetchData.razor

@page "/fetchdata"
@using BlazingDemo.Client.Models
@using AspNetMonsters.Blazor.Geolocation

@inject HttpClient Http
@inject LocationService LocationService

<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>

<div>
    <EditForm Model="@weatherForm" OnValidSubmit="@GetWeatherDataAsync">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <InputText Id="cityName" bind-Value="@weatherForm.CityName" />
        <button type="submit">Submit</button>
    </EditForm>
</div>
<br />

@if (weatherData == null)
{
    <Loader/>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>City</th>
                <th>Conditions</th>
                <th>Temp. (C)</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>@weatherData.Name</td>
                <td>@weatherData.Weather[0].Main</td>
                <td>@weatherData.Main.Temp</td>
            </tr>
        </tbody>
    </table>
}

@functions {

    WeatherFormModel weatherForm = new WeatherFormModel();
    WeatherData weatherData;
    Location location;

    protected override async Task OnInitAsync()
    {
        location = await LocationService.GetLocationAsync();

        if (location != null)
        {
            weatherData = await GetWeatherDataAsync(location.Latitude,location.Longitude);
        }
    }

    protected async Task<WeatherData> GetWeatherDataAsync(decimal latitude, decimal longitude)
    {
        return await Http.GetJsonAsync<WeatherData>($"https://api.openweathermap.org/data/2.5/weather?lat={location.Latitude}&lon={location.Longitude}&units=metric&appid=***removed***");
    }

    protected async void GetWeatherDataAsync()
    {
        weatherData = await Http.GetJsonAsync<WeatherData>($"https://api.openweathermap.org/data/2.5/weather?q={weatherForm.CityName}&units=metric&appid=***removed***");
    }
}

WeatherFormModel.cs

namespace BlazingDemo.Client.Models
{
    public class WeatherFormModel
    {
        [Required, Display(Name = "City Name")]
        public string CityName { get; set; }

        public bool IsCelcius { get; set; }
    }
}

I'm calling the GetWEatherDataAsync() method and I can see the data being returned from the API on each call by inspecting Chrome's return JSON data. It just never updates the table on the first click. I've also tried setting weatherData to null before calling the method but that doesn't work either.

Any suggestions?


回答1:


When you hit the "submit" button, the GetWeatherDataAsync() method is called, and it retrieves the data into the weatherData variable... and ends its mission...

Ordinarily, components are re-rendered after their events have been triggered; that is, there is no need to manually call the StateHasChanged() method to re-render the component. It is automatically called by Blazor. But in this case, you do need to manually add the StateHasChanged() method in order to re-render the component. Thus your code should be like this:

protected async void GetWeatherDataAsync()
    {
        weatherData = await Http.GetJsonAsync<WeatherData>($"https://api.openweathermap.org/data/2.5/weather?q={weatherForm.CityName}&units=metric&appid=***removed***");

        StateHasChanged();
    }

The "submit" event is the only event in Blazor that his action is prevented by default by Blazor. The "submit" event does not really post the form to the server. See: https://github.com/aspnet/AspNetCore/blob/master/src/Components/Browser.JS/src/Rendering/BrowserRenderer.ts . So it seems to me..., it's only a guess, that Blazor treats it differently, and does not call the StateHasChanged method to refresh the component.




回答2:


The reason the StateHasChanged() call was necessary here is because the GetWeatherDataAsync() method you were referring to is void. So there was no a way for the server to know when the call has completed. So the original form submit request finished earlier than the weather data was populated. Hence, the call to StateHasChanged() would indicate the server that there is a need to rerender the component and that would work just fine. In general, you should simply avoid using async void (unless you know it's truly a fire-and-forget situation) and return some type of Task instead, which would eliminate the need for the explicit StateHasChanged() call.



来源:https://stackoverflow.com/questions/56436577/blazor-form-submit-needs-two-clicks-to-refresh-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!