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

如何在Fluxor中实现Selector?Blazor应用状态管理问题

Fluxor Selector 用法及非组件类状态同步问题解决

核心问题原因

你遇到的服务类中IState不同步的问题和Selector没有直接关系,核心原因是:

  • IState<TState>本身是全局单例,状态更新后它的Value属性会同步更新,你看到的“不同步”大概率是你的服务类为单例生命周期,仅在构造函数中读取了一次State.Value存入本地变量,后续调用逻辑时没有重新读取Value导致的
  • FluxorComponent内部默认订阅了IState.StateChanged事件,状态变更时会自动触发组件重绘,普通服务类没有这个自动订阅逻辑,需要手动处理
  • 不需要通过注册瞬时服务的方式规避:如果你的服务类不需要状态变更时自动触发逻辑,仅在被调用时需要获取最新状态,每次调用时直接读取IState<TState>.Value即可

Selector 标准用法

Selector 是用来从全局状态中提取派生数据的工具,自带缓存逻辑,只有当依赖的状态片段发生变更时才会重新计算派生值,避免不必要的重复计算。

基础无依赖 Selector

首先定义状态结构:

// 状态定义
public record AppState
{
    public List<Book> Books { get; init; } = [];
    public bool IsLoading { get; init; }
    public string CurrentFilter { get; init; } = string.Empty;
}

public record Book(string Title, bool IsPublished);

定义单字段派生 Selector:

// 从AppState提取所有已上架图书的Selector
public static readonly ISelector<AppState, List<Book>> PublishedBooksSelector =
    SelectorFactory.Create<AppState, List<Book>>(
        state => state.Books.Where(b => b.IsPublished).ToList()
    );

调用方式:

// 注入IState<AppState>后调用,直接获取最新派生值
var publishedBooks = PublishedBooksSelector.Select(State.Value);

带依赖的组合 Selector

如果派生值依赖多个其他Selector的结果,可以用组合方式实现,自动跟踪依赖变更,只有依赖项返回值变化时才会重新计算:

// 先定义提取当前筛选条件的子Selector
public static readonly ISelector<AppState, string> CurrentFilterSelector =
    SelectorFactory.Create<AppState, string>(state => state.CurrentFilter);

// 组合两个子Selector,生成筛选后的已上架图书Selector
public static readonly ISelector<AppState, List<Book>> FilteredPublishedBooksSelector =
    SelectorFactory.Create(
        PublishedBooksSelector,
        CurrentFilterSelector,
        (publishedBooks, filter) => 
            publishedBooks.Where(b => b.Title.Contains(filter, StringComparison.OrdinalIgnoreCase)).ToList()
    );

SelectorProtocol 适用场景

SelectorProtocol 是用来在不同状态切片之间共享Selector逻辑的工具,适合多个状态切片存在相同字段、需要复用派生逻辑的场景:

// 定义状态协议接口
public interface ILoadingState
{
    bool IsLoading { get; }
}

// 定义协议对应的通用Selector
public static class LoadingStateSelectors
{
    public static readonly ISelectorProtocol<ILoadingState, bool> IsLoadingSelector =
        SelectorProtocol.Create<ILoadingState, bool>(state => state.IsLoading);
}

// 任意实现了协议的状态切片都可以直接复用这个Selector
public record BookState : ILoadingState
{
    public bool IsLoading { get; init; }
    public List<Book> Books { get; init; } = [];
}

public record UserState : ILoadingState
{
    public bool IsLoading { get; init; }
    public string UserName { get; init; } = string.Empty;
}

// 使用方式
var bookLoading = LoadingStateSelectors.IsLoadingSelector.Select(bookStateInstance);
var userLoading = LoadingStateSelectors.IsLoadingSelector.Select(userStateInstance);

服务类状态自动同步实现

如果需要在服务类中监听状态变更自动执行业务逻辑,手动订阅StateChanged事件即可:

public class BookService : IDisposable
{
    private readonly IState<AppState> _appState;
    private IDisposable? _stateSubscription;

    public BookService(IState<AppState> appState)
    {
        _appState = appState;
        // 订阅状态变更事件
        _stateSubscription = _appState.StateChanged.Subscribe(args =>
        {
            // 状态变更时自动执行逻辑,可直接使用Selector获取最新派生值
            var filteredBooks = FilteredPublishedBooksSelector.Select(args.NewState);
            UpdateLocalBookCache(filteredBooks);
        });
    }

    private void UpdateLocalBookCache(List<Book> books)
    {
        // 业务逻辑实现
    }

    public void Dispose()
    {
        // 释放订阅避免内存泄漏
        _stateSubscription?.Dispose();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:27:00