NgRx Reducer问题:修改数组中指定University对象的状态
问题解决:NgRx中修改指定University的total_students值
核心问题梳理
你的代码存在几个关键问题:
university.reducer.ts中定义了UniversityState接口,但初始状态却使用了Array<University>,类型不匹配- 修改学生总数的逻辑放错了位置,应该在维护大学列表的
universityReducer中处理,而非collectionReducer(该reducer是官方书籍教程遗留的,用于维护收藏ID列表,和当前修改学生总数的需求无关) - 状态更新逻辑错误,未遵循NgRx不可变更新的原则
修正后的代码实现
1. 修正 Reducers/university.reducer.ts
统一状态结构,并添加修改学生总数的reducer逻辑:
import { createReducer, on } from '@ngrx/store'; import { UniversityActions, UniversityApiActions } from '@actions/actions/university.actions'; import { University } from '@models/university.model'; export interface UniversityState { universities: University[]; status: 'start' | 'loading' | 'error' | 'success'; error: string | null; } // 初始状态严格匹配接口结构 export const initialState: UniversityState = { universities: [], status: 'start', error: null }; export const universityReducer = createReducer( initialState, // 处理获取大学列表的动作 on(UniversityApiActions.retrievedUniversities, (state, { universities }) => ({ ...state, universities, status: 'success' })), // 处理修改学生总数的动作 on(UniversityActions.changeStudentTotal, (state, { universityId, total_students }) => ({ ...state, // 不可变更新:遍历数组,找到目标ID的大学后创建新对象 universities: state.universities.map(university => { if (university.id === universityId) { // 复制原属性并更新total_students return { ...university, total_students }; } // 其他大学直接返回原对象 return university; }) })) );
2. 调整 Reducers/collection.reducer.ts(可选)
如果你的需求不需要维护收藏的大学ID列表,可以直接删除这个reducer;如果需要保留,注意该reducer的状态是string[],和修改学生总数的动作无关,无需在其中处理changeStudentTotal。
3. 修正 Selectors/university.selectors.ts
由于状态结构改为UniversityState,调整选择器以匹配新结构:
import { createSelector, createFeatureSelector } from '@ngrx/store'; import { University } from '@models/university.model'; import { UniversityState } from '@state/reducers/university.reducer'; // 获取整个UniversityState export const selectUniversityState = createFeatureSelector<UniversityState>('universities'); // 获取所有大学列表 export const selectAllUniversities = createSelector( selectUniversityState, (state) => state.universities ); // 根据ID获取单个大学(可选) export const selectUniversityById = (universityId: string) => createSelector( selectAllUniversities, (universities) => universities.find(u => u.id === universityId) ); // 原收藏列表选择器(保留collectionReducer时使用) export const selectCollectionState = createFeatureSelector<Array<string>>('collection'); export const selectCollectionUniversities = createSelector( selectAllUniversities, selectCollectionState, (universities, collection) => { return collection.map(id => universities.find(u => u.id === id)!); } );
4. 动作部分无需修改
你定义的university.actions.ts是正确的,changeStudentTotal动作携带的universityId和total_students参数完全匹配需求。
关键逻辑说明
NgRx要求状态更新必须是不可变的,所以不能直接修改原数组或对象:
- 使用扩展运算符
...复制原状态对象,保留未修改的属性 - 使用
map遍历大学数组,找到目标ID的大学时,创建新对象(复制原属性+更新total_students),其他对象直接返回 - 既保证了状态的不可变性,又正确完成了指定大学的学生总数更新
内容的提问来源于stack exchange,提问作者Scottish Smile
相关产品推荐
相关产品推荐

