You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor页面跳转时如何避免状态重置,保留原有数据与运行状态?

问题根因

Blazor的默认路由逻辑下,当你导航离开当前页面组件时,原组件实例会触发销毁生命周期被释放,再次导航回该页面时会创建全新的组件实例,因此组件内的字段、运行中的循环任务都会被完全重置,你观察到的现象是完全符合框架默认行为的。

可用解决方案

方案1:将状态和运行逻辑托管到服务中(最推荐,适合复杂、需要长期运行的场景)

你可以将WebSocket的运行逻辑、状态数据都托管到DI容器的服务中,服务的生命周期不受组件销毁的影响,同个会话/全局内可以共享状态。

  1. 首先创建状态服务类
// 自定义状态服务类
public class WebSocketDataService : IDisposable
{
    // 持久化存储Content状态
    public string Content { get; private set; }
    private bool _taskCancel = false;
    private Task _runningSocketTask;
    // 状态更新通知事件,用于通知关联组件刷新
    public event Action OnContentUpdated;

    public async Task StartSocketLoopAsync()
    {
        // 避免重复启动循环
        if (_runningSocketTask is { IsCompleted: false }) return;
        _taskCancel = false;
        _runningSocketTask = RunLoopInternal();
        await _runningSocketTask;
    }

    private async Task RunLoopInternal()
    {
        while (!_taskCancel)
        {
            Content = await webSocket.SendAsync(/*你的原有逻辑*/);
            OnContentUpdated?.Invoke();
            await Task.Delay(15000);
        }
    }

    public void Dispose()
    {
        _taskCancel = true;
        _runningSocketTask?.Dispose();
    }
}
  1. 在Program.cs中注册服务
// Blazor Server场景用AddScoped,每个用户连接独享一份服务实例
// Blazor WASM场景用AddSingleton即可,单用户全局唯一
builder.Services.AddScoped<WebSocketDataService>();
  1. 修改你的Razor页面,直接使用服务中的状态和逻辑
@inject WebSocketDataService SocketService
@implements IDisposable

<p>Result @SocketService.Content</p>

@code {
    protected override async Task OnInitializedAsync()
    {
        // 订阅状态更新事件,触发组件刷新
        SocketService.OnContentUpdated += StateHasChanged;
        await SocketService.StartSocketLoopAsync();
    }

    public void Dispose()
    {
        // 销毁时取消订阅,避免内存泄漏
        SocketService.OnContentUpdated -= StateHasChanged;
    }
}

该方案的优势是状态完全和组件生命周期解耦,只要服务不销毁,状态和运行中的WebSocket循环都会持续工作,也支持跨组件共享同一份数据。

方案2:使用Blazor内置PersistentComponentState(适合轻量状态持久化,.NET 6+支持)

如果你的场景不需要WebSocket循环在后台持续运行,只需要保留跳转前的内容状态,可以用框架自带的状态持久化工具:

@inject PersistentComponentState PersistState
@implements IDisposable

<p>Result @Content</p>

@code {
    private string Content;
    private bool taskCancel = false;
    private PersistingComponentStateSubscription _stateSubscription;

    protected override void OnInitialized()
    {
        // 注册状态持久化回调,导航离开时自动存状态
        _stateSubscription = PersistState.RegisterOnPersisting(() =>
        {
            PersistState.PersistAsJson(nameof(Content), Content);
            return Task.CompletedTask;
        });

        // 组件初始化时尝试读取之前保存的状态
        if (PersistState.TryTakeFromJson<string>(nameof(Content), out var savedContent))
        {
            Content = savedContent;
        }

        // 你的原有StartAsync逻辑可以在这里继续执行
    }

    public void Dispose()
    {
        // 记得销毁时取消循环,避免内存泄漏
        taskCancel = true;
        _stateSubscription.Dispose();
    }
}

注意事项

你的原有代码中的while循环如果没有在组件销毁时取消,会导致旧组件实例无法被回收,出现内存泄漏和重复请求的问题,无论用哪种方案都要记得在组件的Dispose生命周期中设置取消标记,释放循环相关资源。

内容的提问来源于stack exchange,提问作者qalooi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 16:24:03