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], []
修复方案
问题根源
- 分类数据被商品请求清空:
getAllProducts对应的三个action(GET_ALL_PRODUCTS、GET_PRODUCTS_ERROR、GET_PRODUCTS_SUCCESS)都会把categories重置为空数组。由于两个请求是并行发送的,如果分类请求先完成,categories被填充,但之后商品请求完成时会将其清空,导致分类不显示。 - 不必要的状态合并:
getAllCategories里从当前state取现有分类再和新数据合并,完全没必要,初始状态分类是空的,重复请求还会导致数据重复。 - 加载状态未正确处理:分类请求的加载和错误状态没有更新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
相关产品推荐
相关产品推荐

