简体   繁体   English

Blazor(客户端)StateHasChanged() 不更新页面

[英]Blazor (Client-side) StateHasChanged() not updating page

I have a button on my page (component) that calls a Refresh() method when clicked.我的页面(组件)上有一个按钮,单击时会调用 Refresh() 方法。 This method then calls the StateHasChanged(), but does not reload the page.此方法然后调用 StateHasChanged(),但不会重新加载页面。 The GetData() is calling an external API to load data from a database. GetData() 正在调用外部 API 以从数据库加载数据。

<button class="btn btn-warning" @onclick="Refresh">Refresh</button>

code {

protected override async Task OnInitializedAsync()
    {
        try
        {
            await GetData();
            base.OnInitialized();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

    }

protected async Task GetData()
    {
        try
        {
            results = await HttpClient.GetJsonAsync<Results[]>(ServiceEndpoints.GET_RESULTS);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error retrieving data from Oracle.", ex.Message);
        }
    }

public void Refresh()
        {
            StateHasChanged();          
        }

My page (component) also has a form that has preloaded inputs that can be changed.我的页面(组件)还有一个表单,该表单具有可以更改的预加载输入。 I want the user to be able to edit the form, but be able to refresh the page by clicking the button to get back the original data.我希望用户能够编辑表单,但能够通过单击按钮来刷新页面以取回原始数据。 This was working on a previous version of Blazor, is there a known issue about this?这是在以前版本的 Blazor 上工作的,是否存在已知问题?

@page "/"
@inherits IndexBase

<EditForm Model="@results">
<label><strong>Select a job to view its current parameters</strong></label>
<div class="currentJobForm">

    <InputSelect id="jobSelect" @bind-Value="jobSelected">
        @foreach (var items in results)
        {
            <option value="@items.JOB_NAME">@items.JOB_NAME</option>
        }
    </InputSelect>
    <button class="btn btn-warning" @onclick="SaveChanges" disabled="@IsDisabled">Save</button>
    <button class="btn btn-warning" @onclick="Refresh">Refresh</button>
    <button class="btn btn-danger" @onclick="DeleteJob">Delete Job</button>
</div>    
    <label><strong>Notify Parameters</strong></label>
    <div class="notifyParametersForm">
        @foreach (var item in results.Where(i => i.JOB_NAME == jobSelected))
        {
            <div class="issueDescription">
                <label><strong>Issue Description</strong></label>
                <InputText id="issueDesc" @bind-Value="item.JOB_HEADER" placeholder="Enter New Issue Description" />
            </div>
            <div class="sendSlack">
                <label><strong>Send Slack</strong></label>
                <InputSelect id="sendSlackSelect" @bind-Value="item.SENDSLACK">
                    @foreach (var items in InitializeData.SendSlacks)
                    {
                        <option value="@items.SendSlackName">@items.SendSlackName</option>
                    }                        
                </InputSelect>
            </div>
            <div class="slackUser">
                <label><strong>Slack User</strong></label>
                <InputText id="slackUser" @bind-Value="item.SLACK_USER" placeholder="Enter New Slack User" />
            </div>
            <div class="slackChannel">
                <label><strong>Slack Channel</strong></label>
                <InputSelect id="sendSlackChannel" @bind-Value="item.SLACK_CHANNEL">
                    @foreach (var items in InitializeData.SlackChannels)
                    {
                        <option value="@items.SlackChannelName">@items.SlackChannelName</option>
                    }                        
                </InputSelect>
            </div>
            <div class="slackUrl">
                <label><strong>Slack URL</strong></label>
                <InputText id="slackUrlTextBox" @bind-Value="item.SLACK_URL" placeholder="Enter New Slack Url" />
            </div>
            <div class="sendMail">
                <label><strong>Send Mail</strong></label>
                <InputSelect id="sendMailSelect" @bind-Value="item.SENDMAIL">
                    @foreach (var items in InitializeData.SendMails)
                    {
                        <option value="@items.SendMailName">@items.SendMailName</option>
                    }
                </InputSelect>
            </div>
            <div class="mailFrom">
                <label><strong>From:</strong></label>
                <InputText id="from" @bind-Value="item.MAILFROM" placeholder="Enter New Mail From" />
            </div>
            <div class="mailTo">
                <label><strong>To:</strong></label>
                <InputText id="to" @bind-Value="item.MAILTO" placeholder="Enter New Mail To" />
            </div>
            <div class="subject">
                <label id="subjectLabel"><strong>Subject:</strong></label>
                <InputText id="subject" @bind-Value="item.EMAIL_SUBJECT" placeholder="Enter New Subject" />
            </div>
        }
    </div>
</div>

As All the other answers explain there are various way to properly reset your form but none of them except BrinkDaDrink answer tell you how to refresh the page with a press of a button.正如所有其他答案所解释的那样,有多种方法可以正确重置您的表单,但除了 BrinkDaDrink 答案之外,没有一种方法会告诉您如何通过按一下按钮来刷新页面。

BrinkDaDrink answer add unnecessary complexity in my opinion.在我看来,BrinkDaDrink 答案增加了不必要的复杂性。

My solution is to create an empty component page called refresh as follows:我的解决方案是创建一个名为 refresh 的空组件页面,如下所示:

@page "/refresh"
@inject NavigationManager NavigationManager

@code {

    protected override void OnInitialized()
    {
        NavigationManager.NavigateTo("");
    }

}

This page will immediately redirect to your original page refreshing the page and all of the data instantly.此页面将立即重定向到您的原始页面,立即刷新页面和所有数据。

You can create a refresh method in your original page as follows:您可以在原始页面中创建刷新方法,如下所示:

public void RefreshPage()
{
    NavigationManager.NavigateTo("refresh");
}

This solves the issue you mention much faster than any of the other solutions provided so far:这比迄今为止提供的任何其他解决方案更快地解决您提到的问题:

I want the user to be able to edit the form, but be able to refresh the page by clicking the button to get back the original data我希望用户能够编辑表单,但能够通过单击按钮来刷新页面以取回原始数据

You can also use this to pass parameters into your refresh page by adding the following to the refresh page:您还可以使用它通过将以下内容添加到刷新页面来将参数传递到刷新页面:

@page "/refresh"
@page "/refresh/{text}"
@inject NavigationManager NavigationManager

@code {
    [Parameter]
    public string Text { get; set; }

    protected override void OnInitialized()
    {
        NavigationManager.NavigateTo(Text);
    }

}

You need to set your values back to their original values.您需要将值设置回其原始值。 StateHasChanged does not refresh the page. StateHasChanged不会刷新页面。 It resets the component to check the RenderTree to see if dom elements should be updated - but since your values have not changed it will not update the way you are looking for.它重置组件以检查 RenderTree 以查看是否应该更新 dom 元素 - 但由于您的值没有更改,因此不会更新您正在寻找的方式。

Calling GetData() instead of StateHasChanged should work in your case, but you may want to store the values instead of hitting the API again.调用GetData()而不是StateHasChanged应该适用于您的情况,但您可能希望存储值而不是再次点击 API。

I simplified your code to provide a working example:我简化了您的代码以提供一个工作示例:

    @page  "/update-test"
<EditForm Model="@Item">
    <div class="notifyParametersForm">
    </div>
    <div class="mailFrom">
        <label><strong>From:</strong></label>
        <InputText id="from" @bind-Value="Item.MAILFROM" placeholder="Enter New Mail From" />
    </div>
    <div class="mailTo">
        <label><strong>To:</strong></label>
        <InputText id="to" @bind-Value="Item.MAILTO" placeholder="Enter New Mail To" />
    </div>
    <div class="subject">
        <label id="subjectLabel"><strong>Subject:</strong></label>
        <InputText id="subject" @bind-Value="Item.EMAIL_SUBJECT" placeholder="Enter New Subject" />
    </div>

    <button class="btn btn-warning" @onclick="ResetInputs">Refresh</button>
</EditForm>

@code {


    EmailItem Item;
    protected override async Task OnInitializedAsync()
    {
        try
        {
            GetData();
            base.OnInitialized();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

    }

    protected void GetData()
    {
        Item = new EmailItem()
        {
            MAILFROM = "testfrom@test.com",
            MAILTO = "testto@test.com",
            EMAIL_SUBJECT = "subject",
        };
    }

    public void ResetInputs()
    {
        GetData();
    }

    public class EmailItem
    {
        public string MAILTO { get; set; }
        public string MAILFROM { get; set; }
        public string EMAIL_SUBJECT { get; set; }
    }
}

I did it by binding a string value.我是通过绑定一个字符串值来实现的。 You don't have to display the value on the body page for it to work.您不必在正文页面上显示该值即可使其工作。 I change the string from uppercase to lowercase.我将字符串从大写更改为小写。 Funny thing is this only works with a string value.有趣的是,这只适用于字符串值。

NAVMENU ----------------------
  <button type="button" class="btn btn-warning border-secondary" @onclick="runSearch">Search</button>

@code {
    public string pageReload = "Search";

 private void runSearch()
    {
        if (pageReload == "Search") { pageReload = "search"; } else { pageReload = "Search"; }
        NavigationManager.NavigateTo($"/Page2/{pageReload}", false);
    }
}

Page 2------------------------------------------------------------------------

@page "/Datatest2/{pageReload}"

<h1>page will now refresh every time</h1>


@code{
    [Parameter]
    public string pageReload { get; set; }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM