如何在NgRx中按任意属性对实体排序,能否从主store获取sort状态?
实现方案
你无法直接向sortComparer中注入服务或访问全局Store,因为NgRx的Reducer设计为纯函数,不允许引入外部依赖。可以通过以下两种成熟方案实现基于State中排序配置的动态排序:
方案1:在Selector层实现排序(更推荐)
排序属于派生状态,放在Selector中处理是最符合NgRx设计规范的做法,无需修改Reducer和EntityAdapter的初始化逻辑:
- 初始化
EntityAdapter时移除固定的sortComparer配置
// reducer.ts export const adapter: EntityAdapter<ProductDetails> = createEntityAdapter<ProductDetails>(); export const initialState: ProductsState = adapter.getInitialState({ productType: null, productTags: [], sort: { key: 'name', order: 1 } });
- 编写带排序逻辑的Selector,自动关联State中的排序配置
// selector.ts import { createSelector } from '@ngrx/store'; import { selectProductsState } from './products.selectors'; // 先获取原始的全量实体列表 const selectAllProducts = createSelector( selectProductsState, state => adapter.selectAll(state) ); // 关联排序状态,返回排序后的列表 export const selectSortedProducts = createSelector( selectAllProducts, selectProductsState, (products, state) => { const { sort } = state; // 拷贝数组后排序避免修改原引用 return [...products].sort((a, b) => { const itemA = a[sort.key]; const itemB = b[sort.key]; return itemA < itemB ? -1 * sort.order : itemA > itemB ? sort.order : 0; }); } );
该方案的优势:排序逻辑与Reducer解耦,Selector自带缓存机制,仅当实体列表或排序配置变更时才会重新执行排序,性能损耗极低。
方案2:排序配置变更时重新设置实体
如果你需要使用EntityAdapter内置的排序能力,可以在触发排序配置更新的Action处理逻辑中,重新用新的排序规则设置全量实体:
// reducer.ts import { createReducer, on } from '@ngrx/store'; import { updateSort } from './products.actions'; const productsReducer = createReducer( initialState, // 处理更新排序配置的Action on(updateSort, (state, { newSort }) => { // 拿到当前所有实体 const allProducts = adapter.selectAll(state); // 按新排序规则排序后重新存入State return adapter.setAll(allProducts, { ...state, sort: newSort }); }) );
该方案适合实体数量较少的场景,后续调用adapter.selectAll即可直接获取排序后的结果,无需在Selector额外处理。
内容的提问来源于stack exchange,提问作者JanuszFrontEnd'u
相关产品推荐
相关产品推荐

