You need to enable JavaScript to run this app. 如何解决Ngrx reducer中用filter+includes过滤后状态永久变更的问题
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Ngrx reducer中用filter+includes过滤后状态永久变更的问题

问题根源

你当前的写法直接修改了存储原始歌曲列表的状态,每次执行过滤操作都会将状态覆盖为过滤后的子集,原始未匹配数据会被永久删除,自然无法在输入框清空后恢复全量数据。reducer只应该用来存储基础状态,过滤后的列表属于派生状态,不应该在reducer中直接修改原始数据生成。

解决方案

步骤1:调整State结构,拆分基础状态

你需要在状态中同时留存全量原始数据、当前过滤参数,永远不要修改全量原始数据集:

// 首先定义状态类型
export interface DataState {
  allSongs: Songs[]; // 永久存储全量原始歌曲数据,过滤操作不会修改该字段
  filterText: string; // 存储当前输入的过滤关键词
  filterField: string; // 存储当前选中的过滤字段,对应action传入的field参数
}

// 初始状态配置,allSongs赋值为你的全量初始歌曲数据
const initialState: DataState = {
  allSongs: [/* 你的原始全量歌曲数据 */],
  filterText: '',
  filterField: 'artist'
};

步骤2:修改Reducer逻辑,仅更新过滤参数

reducer不再执行过滤操作,只负责更新过滤相关的参数,保留全量原始数据:

export const dataReducer = createReducer<DataState>(
  initialState,
  on(filterTable, (state, action) => {
    return {
      ...state,
      filterText: action.text,
      filterField: action.field
    };
  })
);

步骤3:使用Ngrx Selector生成实时过滤的派生状态

通过Selector基于基础状态实时计算过滤结果,不会修改原始数据,且会随参数变化自动更新:

import { createSelector } from '@ngrx/store';

// 先取到当前模块的状态
const selectDataState = (state: RootState) => state.data; // 这里的RootState替换为你项目的根状态类型

// 导出过滤后的歌曲列表选择器,组件直接订阅该选择器即可
export const selectFilteredSongs = createSelector(
  selectDataState,
  ({ allSongs, filterText, filterField }) => {
    // 过滤关键词为空时直接返回全量数据
    if (!filterText?.trim()) return allSongs;
    const lowerFilterText = filterText.toLowerCase();
    // 基于当前过滤参数实时计算结果
    return allSongs.filter(item => {
      const fieldValue = item[filterField as keyof Songs]?.toString().toLowerCase() || '';
      return fieldValue.includes(lowerFilterText);
    });
  }
);

步骤4:组件中使用

输入框每次输入时只需要触发filterTable action传入最新的输入内容和过滤字段,组件直接订阅selectFilteredSongs获取实时的过滤结果即可,无需手动处理重置逻辑,关键词为空时自动返回全量数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 16:15:00