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

Node.js+React GET接口传参 Reducer接收数据报错咨询

问题根因说明

你遇到的几个报错核心是三个低级问题,和接口传数组/对象的逻辑本身无关:

  1. 第一个totalPages未定义报错:reducer初始状态写法错误,state = {orders:[], totalPages}属于ES6对象简写语法,该写法要求外部已经声明totalPages变量,你没有提前声明就直接写键名,JS会判定为引用不存在的变量直接抛错。
  2. 前后端字段不匹配:第一次后端返回结构是{data: [orders], totalPages},不仅把orders数组额外套了一层数组,返回体里根本没有orders这个键,前端reducer取action.payload.orders自然拿不到值。
  3. 逻辑细节错误:一是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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:18:48