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

如何结合Redux AsyncThunk与Reselect实现自定义GroupBy分组

问题解决:Redux异步数据分组渲染报错处理

问题分析

报错核心原因有两点:

  • API请求完成前,Redux Store中animals初始为空数组,若选择器返回结果未做边界处理,组件直接调用Object.keys(animals)或animals[animal_type].map会因undefined触发报错
  • 当前Reselect选择器在存在activeFilter时未返回任何值,导致组件获取到undefined进而引发逻辑错误

解决方案

1. 完善Reselect选择器,确保始终返回合法对象

修改选择器,处理空数据和activeFilter存在的场景,保证无论何种情况都返回一个可操作的对象:

export const selectAnimalsByFilter = createSelector(
  [selectAllAnimals, selectActiveFilter],
  (allAnimals, activeFilter) => {
    // 先处理空数据/非数组情况,直接返回空对象
    if (!Array.isArray(allAnimals) || allAnimals.length === 0) {
      return {};
    }

    if (!activeFilter) {
      return groupBy(allAnimals, 'animal_type');
    }

    // 若有activeFilter,补充你的过滤逻辑(示例按动物类型过滤,可按需修改)
    return groupBy(
      allAnimals.filter(animal => animal.animal_type === activeFilter),
      'animal_type'
    );
  }
);

2. 增强groupBy函数的健壮性

给groupBy函数添加空数组、属性缺失的判断,避免意外报错:

const groupBy = (xs, key) => {
  // 处理传入非数组或空数组的情况
  if (!Array.isArray(xs) || xs.length === 0) {
    return {};
  }
  
  return xs.reduce(function(rv, x) {
    // 确保当前元素存在目标属性,避免报错
    if (x && x[key]) {
      (rv[x[key]] = rv[x[key]] || []).push(x);
    }
    return rv;
  }, {});
}; 

3. 组件中添加加载/错误/空数据状态处理

在组件中先获取Redux的loading和error状态,根据状态分支渲染,避免数据未就绪时执行渲染逻辑:

// 从Redux获取状态
const animals = useSelector(selectAnimalsByFilter);
const { loading, error } = useSelector(state => state.animals);

// 加载中状态
if (loading) {
  return <div>加载中...</div>;
}

// 错误状态
if (error) {
  return <div>加载失败:{error}</div>;
}

// 空数据状态
const animalTypes = Object.keys(animals);
if (animalTypes.length === 0) {
  return <div>暂无动物数据</div>;
}

// 正常渲染逻辑
const fitOptions = animalTypes.map((animal_type, index) => (
  <Menu.Item key={index}>
    <Accordion.Title
      active={activeIndex === index}
      content={animal_type}
      index={index}
      onClick={() => accordionClick(index)}
    />
    <Accordion.Content active={activeIndex === index} content={
      <Form>
        <Form.Group grouped>
          {animals[animal_type].map((animal) => 
            <Form.Checkbox label={animal.name} name='animal_id' value={animal.id} key={animal.id} />
          )}
        </Form.Group>
      </Form>
    } />
  </Menu.Item>
));

4. 优化Slice初始状态

将loading初始值设为false,避免初始状态下误判为加载中:

const animalSlice = createSlice({
  name: 'animals',
  initialState: {
    animals: [],
    loading: false, // 初始设为false更合理
    error: null,
  },
  extraReducers: {
    [getAnimals.pending]: (state) => {
      state.loading = true;
      state.error = null;
    },
    [getAnimals.fulfilled]: (state, action) => {
      state.loading = false;
      state.animals = action.payload;
    },
    [getAnimals.rejected]: (state, action) => {
      state.loading = false;
      state.error = action.payload;
    },
  }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:25:44