当URL查询变化时,强制Blazor组件重新渲染

4
我读到的所有内容都指向使用NavigationManager.LocationChanged事件,但它无法检测到仅查询字符串更改的情况。因此,没有任何事情触发。
我尝试了建议的here,但那不是我要找的。
每当当前路由中的查询参数更改时,我需要重新呈现我的组件。有人能做到这一点吗?
更新:
这是我的代码示例:
@page "/accounts"

@if (Accounts != null)
{
    <table>
        <tbody>
            @foreach (var account in Accounts)
            {
                <tr>
                    <td>
                        <NavLink href="/accounts/?accountId={account.AccountId}">@Account.Name</NavLink>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}

@if (Account != null)
{
    <div>
        <h2>@Account.Name</h2>
    </div>
}

@implements IDisposable
@inject NavigationManger NavManager
@inject AccountService AccountService

@code {
    protected Guid Id { get; set; } = Guid.NewGid();
    protected Guid AccountId { get; set; } = Guid.Empty;
    protected List<AccountModel> Accounts { get; set; }
    protected AccountModel Account { get; set; }

    protected override void OnInitialized()
    {
        NavManager.LocationChanged += LocationChanged;
    }

    protected async override Task OnParametersSetAsync()
    {
        if (AccountId != Guid.Empty)
        {
            Account = await AccountService.GetAsync(AccountId);
        }
        else
        {
            Accounts = await AccountService.GetAllAsync();
        }
    
        StateHasChanged();
    }

    void LocationChanged(object sender, LocationChangedEventArgs e)
    {
        Id = Guid.NewGuid();
    
        StateHasChanged();
    }
    
    void IDisposable.Dispose()
    {
        NavManager.LocationChanged -= LocationChanged;
    }
}

这里的问题是,当仅更改查询参数时,LocationChanged(object,LocationChangedEventArgs)不会触发。这很有道理,因为路由相同/accounts
基本上,我有一个页面来显示一系列帐户并查看单个帐户。当查看列表时,我希望路由为/accounts,而查看一个帐户时,则应为“/ accounts?accountId = someAccountId”。使用标准的NavLink组件不会触发组件的重新渲染,LocationChanged事件也不会。即使设置了新的ID值也是如此。因为StateHasChanged仅在值更改时才重新呈现组件。

1
你的查询字符串值属性是否带有[SupplyParameterFromQuery]注释?这是必需的,才能使这些属性更新并调用你的OnParametersSet方法(或其异步变体)。 - Kirk Woll
提供一个 [mre] - H H
@KirkWoll 我正在使用 .NET 5,我看到那是 .NET 6 的功能?但我现在还不能升级。 - Jason Ayer
@HenkHolterman 示例已添加。 - Jason Ayer
当应用程序最初加载时,您可以将初始查询字符串参数存储到“ProtectedLocalStorage”或“ProtectedSessionStorage”中。当页面使用新的查询字符串重新提交时,您可以将其与存储进行比较。 - clamchoda
3个回答

5
我最终让我想要的事情像这样工作起来:
@page "/accounts"

@if (Accounts != null)
{
    <table>
        <tbody>
            @foreach (var account in Accounts)
            {
                <tr>
                    <td>
                        <NavLink href="/accounts/?accountId={account.AccountId}">@Account.Name</NavLink>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}

@if (Account != null)
{
    <div>
        <h2>@Account.Name</h2>
    </div>
}

@implements IDisposable
@inject NavigationManger NavManager
@inject AccountService AccountService

@code {
    protected Guid Id { get; set; } = Guid.NewGid();
    protected Guid AccountId { get; set; } = Guid.Empty;
    protected List<AccountModel> Accounts { get; set; }
    protected AccountModel Account { get; set; }

    protected override void OnInitialized()
    {
        NavManager.LocationChanged += LocationChanged;
    }

    protected async override Task OnParametersSetAsync()
    {
        if (AccountId != Guid.Empty)
        {
            Account = await AccountService.GetAsync(AccountId);
        }
        else
        {
            Accounts = await AccountService.GetAllAsync();
        }
    
        StateHasChanged();
    }

    async void LocationChanged(object sender, LocationChangedEventArgs e)
    {
        if (AccountId != Guid.Empty)
        {
            Account = await AccountService.GetAsync(AccountId);
        }
        else
        {
            Accounts = await AccountService.GetAllAsync();
        }
    
        StateHasChanged();
    }
    
    void IDisposable.Dispose()
    {
        NavManager.LocationChanged -= LocationChanged;
    }
}

我最终只是手动调用了所有我想在首次渲染时运行的相同代码。我曾希望(错误地假设)可以通过更改一个本地属性并调用 StateHasChanged 来自动从顶部重新运行组件生命周期。

现在,当我在 "/accounts""/accounts?accountId=someId" 之间切换时,组件会按照我想要的方式重新呈现。


不错,但你本可以调用一个通用的方法而不是重复两次代码。 - Paul Suart
1
也许这就足够了: void LocationChanged(object sender, LocationChangedEventArgs e) => NavManager.NavigateTo(NavManager.Uri, true); - MaxP

1

我可以将以下内容翻译为中文:

在一个 wasm 应用程序中,我成功地执行了这个操作。

将此代码放置在您想要接收路由参数的页面上。

请注意,保留了原始 HTML 标记。

@page "/pagename/{text?}"

<div>@Text</div>

那么

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

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
    protected override void OnParametersSet()
    {
        Text = Text  ?? "Name Not Supplied";
    }
}

据我所知,将重新呈现任何数据更改,您无法强制组件在不重新加载的情况下重新呈现,只有更改的订阅者会重新呈现,这是有道理的,因为重新呈现很昂贵。

文档中查看路由参数。


0
您可以将StateHasChanged()绑定到更改查询字符串的函数/逻辑,这将重新呈现您的组件。

我已经尝试过了,但是只有在组件中的值发生变化时,StateHasChanged才会发生。我更新了我的问题,并提供了一个示例来展示我正在尝试的内容,但它并不起作用。 - Jason Ayer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接