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

React+Redux+TypeScript项目分类加载不稳定问题求助

问题描述

我在项目中使用React、Redux及TypeScript,通过以下代码获取商品及其分类。商品加载正常,但分类加载存在异常:有时需多次刷新页面才能显示,有时无法显示。请告知修复方法,非常感谢。

ApiService 代码

export const getAllCategories = () => {
    return async (dispatch: Dispatch<ProductActionModel>, getState: () => RootState) => {
        try {
            dispatch({ type: Action_types.GET_ALL_CATEGORIES });
            const response = await fetch(`${environment.baseApiUrl}/products/categories`).then(res => res.json());
            const state = getState();
            dispatch({ type: Action_types.GET_ALL_CATEGORIES_SUCCESS, payload: [...state.products.categories, ...response] });
        } catch (error) {
            dispatch({ type: Action_types.GET_ALL_CATEGORIES_ERROR, payload: 'Something went wrong'})
        }
    }
}


export const getAllProducts = () => {
    return async (dispatch: Dispatch<ProductActionModel>) => {
        try {
            dispatch({ type: Action_types.GET_ALL_PRODUCTS });
            const response = await fetch(`${environment.baseApiUrl}/products`).then(response => response.json())
            dispatch({ type: Action_types.GET_PRODUCTS_SUCCESS, payload: response.products })
        } catch (e) {
            dispatch({ type: Action_types.GET_PRODUCTS_ERROR, payload: 'Something went wrong' });
        }
    }
}

ProductReducer 代码

const initialState: ProductsStateModel = {
    products: [],
    categories: [],
    loading: false,
    error: null
}

export const ProductReducer = (state = initialState, action: ProductActionModel): ProductsStateModel => {
    switch (action.type) {

        case Action_types.GET_ALL_PRODUCTS:
            return { loading: true, error: null, products: [], categories: [] }
        case Action_types.GET_PRODUCTS_ERROR:
            return { loading: false, error: action.payload, products: [], categories: [] }
        case Action_types.GET_PRODUCTS_SUCCESS:
            return { loading: false, error: null, products: action.payload, categories: [] }
        case Action_types.GET_ALL_CATEGORIES:
            return state;
        case Action_types.GET_ALL_CATEGORIES_ERROR:
            return state;
        case Action_types.GET_ALL_CATEGORIES_SUCCESS:
            return { ...state, categories: [...state.categories, ...action.payload] }
        default:
            return state;
    }
}

ProductList 代码

const { products, error, loading, categories } = useTypesSelector(state => state.products);
const dispatch: ThunkDispatch<RootState, void, ProductActionModel> = useDispatch();

useEffect(() => {
    dispatch(getAllProducts());
    dispatch(getAllCategories())
},[dispatch])

console.log(categories); // sometimes fine, sometimes [], [], [categories], []
修复方案

问题根源

  1. 分类数据被商品请求清空:getAllProducts对应的三个action(GET_ALL_PRODUCTS、GET_PRODUCTS_ERROR、GET_PRODUCTS_SUCCESS)都会把categories重置为空数组。由于两个请求是并行发送的,如果分类请求先完成,categories被填充,但之后商品请求完成时会将其清空,导致分类不显示。
  2. 不必要的状态合并:getAllCategories里从当前state取现有分类再和新数据合并,完全没必要,初始状态分类是空的,重复请求还会导致数据重复。
  3. 加载状态未正确处理:分类请求的加载和错误状态没有更新state,导致页面加载状态不统一。

具体修复步骤

1. 修改ProductReducer,避免清空categories

将商品相关action的返回值改为保留现有categories:

case Action_types.GET_ALL_PRODUCTS:
    return { ...state, loading: true, error: null, products: [] }
case Action_types.GET_PRODUCTS_ERROR:
    return { ...state, loading: false, error: action.payload, products: [] }
case Action_types.GET_PRODUCTS_SUCCESS:
    return { ...state, loading: false, error: null, products: action.payload }

2. 简化getAllCategories逻辑,移除不必要的state合并

不需要从getState取现有分类,直接用接口返回的数据作为payload:

export const getAllCategories = () => {
    return async (dispatch: Dispatch<ProductActionModel>) => {
        try {
            dispatch({ type: Action_types.GET_ALL_CATEGORIES });
            const response = await fetch(`${environment.baseApiUrl}/products/categories`).then(res => res.json());
            dispatch({ type: Action_types.GET_ALL_CATEGORIES_SUCCESS, payload: response });
        } catch (error) {
            dispatch({ type: Action_types.GET_ALL_CATEGORIES_ERROR, payload: 'Something went wrong'})
        }
    }
}

3. 优化分类相关的Reducer逻辑

更新分类请求的加载和错误状态,同时简化成功时的赋值逻辑:

case Action_types.GET_ALL_CATEGORIES:
    return { ...state, loading: true, error: null }
case Action_types.GET_ALL_CATEGORIES_ERROR:
    return { ...state, loading: false, error: action.payload }
case Action_types.GET_ALL_CATEGORIES_SUCCESS:
    return { ...state, loading: false, categories: action.payload }

完成以上修改后,两个请求的状态不会互相干扰,分类数据能稳定显示,同时页面的加载状态也会更准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 13:57:56