Node.js+React GET接口传参 Reducer接收数据报错咨询
问题根因说明
你遇到的几个报错核心是三个低级问题,和接口传数组/对象的逻辑本身无关:
- 第一个
totalPages未定义报错:reducer初始状态写法错误,state = {orders:[], totalPages}属于ES6对象简写语法,该写法要求外部已经声明totalPages变量,你没有提前声明就直接写键名,JS会判定为引用不存在的变量直接抛错。 - 前后端字段不匹配:第一次后端返回结构是
{data: [orders], totalPages},不仅把orders数组额外套了一层数组,返回体里根本没有orders这个键,前端reducer取action.payload.orders自然拿不到值。 - 逻辑细节错误:一是mongoose分页
skip计算逻辑错误,第一页直接跳过20条数据返回空;二是调用action时没传page参数、统计总条数没加用户筛选条件,导致返回数据不符合预期。
正确实现代码
1. 后端接口修正
统一返回结构,修复分页逻辑、统计逻辑:
// orderRouter.js orderRouter.get( '/mine', isAuth, expressAsyncHandler(async (req, res) => { // query参数默认是字符串,先转数字 const page = Number(req.query.page) || 1; const perPage = 20; // 分页skip公式固定为(当前页码-1)*每页条数,否则第一页会跳过perPage条数据 const orders = await Order.find({ user: req.user._id }) .skip((page - 1) * perPage) .limit(perPage); // 统计条数必须加和查询一致的筛选条件,否则统计的是全平台所有订单数,不是当前用户的 const total = await Order.countDocuments({ user: req.user._id }); const totalPages = Math.ceil(total / perPage); // 直接返回明确字段,不要额外套多余层级 res.status(200).send({ orders, // 直接返回查询到的数组,不要额外包[] totalPages }); }) );
2. Reducer修正
补全初始值,字段和后端返回一一对应:
// orderReducer.js export const orderMineListReducer = ( // 所有用到的字段都给明确初始值,不要只写键名不赋值 state = { orders: [], totalPages: 0, loading: false, error: null }, action ) => { switch (action.type) { case ORDER_MINE_LIST_REQUEST: return { ...state, loading: true, error: null }; case ORDER_MINE_LIST_SUCCESS: return { ...state, loading: false, orders: action.payload.orders, totalPages: action.payload.totalPages }; case ORDER_MINE_LIST_FAIL: return { ...state, loading: false, error: action.payload }; default: return state; } };
3. Action修正
给page参数加默认值,确保请求正常发送:
// orderActions.js export const listOrderMine = (page = 1) => async (dispatch, getState) => { dispatch({ type: ORDER_MINE_LIST_REQUEST }); const { userSignin: { userInfo } } = getState(); try { const { data } = await Axios.get( `${BASE_URL}/api/orders/mine?page=${page}`, { headers: { Authorization: `Bearer ${userInfo.token}` } } ); // axios默认把接口返回的JSON体存在data字段里,直接当payload传递即可 dispatch({ type: ORDER_MINE_LIST_SUCCESS, payload: data }); } catch (error) { const message = error.response && error.response.data.message ? error.response.data.message : error.message; dispatch({ type: ORDER_MINE_LIST_FAIL, payload: message }); } };
4. 页面取数修正
直接从store解构对应字段,不要额外包data层:
// OrderHistoryScreen.js const orderMineList = useSelector((state) => state.orderMineList); const { loading, orders, totalPages, error } = orderMineList; const dispatch = useDispatch(); useEffect(() => { // 默认查第一页,翻页时传入对应页码即可 dispatch(listOrderMine(1)); }, [dispatch]); // 此时打印orders、totalPages即可拿到正常返回值 console.log(orders, totalPages);
注意事项
- 后端返回的字段名必须和前端reducer取值的字段名完全一致,大小写也要对齐
- 不要在接口返回体里套无意义的层级,减少前后端字段对齐成本
- reducer初始状态必须给所有用到的字段设置合法初始值,避免组件渲染时取到undefined报错
内容的提问来源于stack exchange,提问作者pelotador.1
相关产品推荐
相关产品推荐

