Redux reducer中workouts调用filter/map报错的修复方案
报错根因
filter is not a function、map is not a function 报错的直接原因是Redux中维护的workouts状态预期为数组类型,但实际被赋值为对象类型,所有数组原生方法无法在非数组类型上调用。
问题出在两个位置:
- 所有接口请求的响应值没有正确解构:你使用的axios类请求工具会把后端返回的实际数据包裹在响应对象的
data字段中,当前代码直接把整个响应对象作为payload传给reducer,首次执行FETCH_ALL时就把workouts状态设置成了对象,后续所有调用数组方法的操作都会触发报错。 - reducer没有做类型校验兜底,一旦传入异常类型的payload,状态会直接变成非数组,触发连锁报错。
具体修改方案
1. 修正actions中的接口响应解构
所有调用api的位置,都需要从响应对象中解构出实际返回的业务数据,不要直接传递整个响应对象:
import { FETCH_ALL, CREATE, UPDATE, DELETE, LIKE, COMMENT_WORKOUT, COMMENT_MEAL } from '../constants/actionTypes'; import * as api from '../api'; export const getWorkouts=()=> async (dispatch)=>{ try{ // 从axios响应中解构出实际数据 const { data } = await api.fetchWorkouts(); dispatch({type:FETCH_ALL,payload:data}); console.log(data); }catch(error){ console.log(error); } } export const getWorkoutsBySearch=(searchQuery)=>async(dispatch)=>{ try{ const {data:{data}}=await api.fetchWorkoutsBySearch(searchQuery); // 后续如果要对接搜索列表渲染,记得在这里dispatch对应action,传入数组类型的data console.log(data); }catch(error){ console.log(error); } } export const createWorkout=(workout)=>async(dispatch)=>{ try{ // 解构新建完成返回的单条workout数据 const { data } = await api.createWorkout(workout); dispatch({type:CREATE,payload:data}); console.log(data); }catch(error){ console.log(error.message); } } export const updateWorkout=(id,workout)=>async(dispatch)=>{ try{ // 解构更新完成返回的单条workout数据 const { data } = await api.updateWorkout(id,workout); dispatch({type:UPDATE,payload:data}) }catch(error){ console.log(error); } } export const deleteWorkout = (id) => async (dispatch) => { try { await api.deleteWorkout(id); dispatch({ type: DELETE, payload: id }); } catch (error) { console.log(error); } }; export const likeWorkout=(id)=>async(dispatch)=>{ try{ // 解构点赞完成返回的单条workout数据 const { data } = await api.likeWorkout(id); console.log(data) dispatch({type:LIKE,payload:data}) }catch(error){ console.log(error); } } export const postCommentOnWorkout=(data)=>async(dispatch)=>{ try{ // 解构评论提交完成返回的单条workout数据 const { data: updatedWorkout } = await api.postCommentOnWorkout(data); dispatch({type:COMMENT_WORKOUT,payload:updatedWorkout}) }catch(error){ console.log(error); } } export const postCommentOnMeal=(data)=>async(dispatch)=>{ try{ // 解构餐食评论提交完成返回的数据 const { data: updatedMeal } = await api.postCommentOnMeal(data); dispatch({type:COMMENT_MEAL,payload:updatedMeal}) }catch(error){ console.log(error); } }
2. 给reducer增加类型兜底
在reducer中增加数组类型校验,避免异常payload导致状态类型错误:
import { FETCH_ALL, CREATE, UPDATE, DELETE, LIKE, COMMENT_WORKOUT } from '../constants/actionTypes'; export default (workouts=[],action)=>{ switch(action.type){ case FETCH_ALL: // 确保存入状态的是数组,异常情况兜底为空数组 return Array.isArray(action.payload) ? action.payload : []; case CREATE: return [...workouts, action.payload]; case UPDATE: return Array.isArray(workouts) ? workouts.map((workout) => workout._id === action.payload._id ? action.payload : workout) : []; case LIKE: return Array.isArray(workouts) ? workouts.map((workout) => workout._id === action.payload._id ? action.payload : workout) : []; case DELETE: return Array.isArray(workouts) ? workouts.filter((workout) => workout._id !== action.payload) : []; case COMMENT_WORKOUT: return Array.isArray(workouts) ? workouts.map((workout) => workout._id === action.payload._id ? action.payload : workout) : []; default: return workouts; } }
验证方式
修改完成后,在FETCH_ALL对应的dispatch位置打日志,确认传入的payload是workout对象组成的数组,后续增删改查、点赞、评论操作就可以正常调用map、filter方法,不会再触发类型报错。
内容的提问来源于stack exchange,提问作者Alexandra DDT
相关产品推荐
相关产品推荐

