如何基于表格列对createEntityAdapter的实体进行排序?
问题根因
- Redux Toolkit的
entityAdapter的sortComparer是创建adapter时的静态配置项,不会自动读取你后续存到state里的sortComparer字段。你在reducer里修改state的sortComparer属性,不会影响getSelectors返回的排序逻辑,是排序不生效的核心原因。 - 你代码中的字符串比较方法拼写错误,
localCompare应为localeCompare,拼写错误也会导致排序逻辑异常。
解决方案
步骤1:在slice state中定义排序配置
不要尝试动态修改adapter的静态sortComparer,而是把排序字段、排序方向存在slice的state中:
import { createSlice, createEntityAdapter, EntityState } from '@reduxjs/toolkit'; // 你的实体类型 type MyEntityType = { id: string; title: string; // 其他业务字段 } // 初始化entityAdapter,不需要传入静态sortComparer const myEntitiesAdapter = createEntityAdapter<MyEntityType>(); // 扩展实体state,新增排序相关字段 interface MyEntitiesState extends EntityState<MyEntityType> { sortKey: keyof MyEntityType; sortOrder: 'asc' | 'desc'; } // 初始化state,给排序参数默认值 const initialState: MyEntitiesState = myEntitiesAdapter.getInitialState({ sortKey: 'title', sortOrder: 'asc' });
步骤2:编写修改排序配置的reducer
直接修改state中的排序参数即可,Redux Toolkit内置的Immer会处理 immutable 逻辑,不需要返回完整state:
const myEntitiesSlice = createSlice({ name: 'myEntities', initialState, reducers: { changeSort: (state, action) => { const targetSortKey = action.payload.sortKey; // 点击相同排序字段则翻转排序方向,点击新字段默认升序 if (state.sortKey === targetSortKey) { state.sortOrder = state.sortOrder === 'asc' ? 'desc' : 'asc'; } else { state.sortKey = targetSortKey; state.sortOrder = 'asc'; } } } }); export const { changeSort } = myEntitiesSlice.actions;
步骤3:封装动态排序的selector
不要直接使用adapter默认的selectAll,自己封装selector根据state中的排序参数动态计算排序后的数据:
// 先获取基础实体查询器 const baseEntitySelectors = myEntitiesAdapter.getSelectors( (state: RootState) => state.myEntities ); // 封装带动态排序的实体查询器 export const selectSortedEntities = (state: RootState) => { const allEntities = baseEntitySelectors.selectAll(state); const { sortKey, sortOrder } = state.myEntities; // 复制数组再排序,避免修改原存储的实体数组 return [...allEntities].sort((a, b) => { // 字符串类型字段排序 if (typeof a[sortKey] === 'string' && typeof b[sortKey] === 'string') { const compareRes = (a[sortKey] as string).localeCompare(b[sortKey] as string); return sortOrder === 'asc' ? compareRes : -compareRes; } // 数字类型字段排序 const compareRes = (a[sortKey] as number) - (b[sortKey] as number); return sortOrder === 'asc' ? compareRes : -compareRes; }); };
步骤4:组件中接入使用
点击表格列时分发修改排序的action,渲染时直接用封装好的排序后数据即可:
import { useDispatch, useSelector } from 'react-redux'; import { changeSort, selectSortedEntities } from './myEntitiesSlice'; function BusinessTable() { const dispatch = useDispatch(); const sortedTableData = useSelector(selectSortedEntities); return ( <table> <thead> <tr> <th onClick={() => dispatch(changeSort({ sortKey: 'title' }))}>标题</th> {/* 其他列绑定对应sortKey即可 */} </tr> </thead> <tbody> {sortedTableData.map(item => ( <tr key={item.id}> <td>{item.title}</td> {/* 其他单元格渲染 */} </tr> ))} </tbody> </table> ); }
内容的提问来源于stack exchange,提问作者DevLoverUmar
相关产品推荐
相关产品推荐

