GET接口返回数组调用filter报Cannot read properties of undefined错误
问题根因
报错由三个问题共同导致:
- 异步渲染时序问题:Redux中
shippingDetails的初始状态未对shipping赋值,默认是undefined。组件首次渲染时,detailsShipping接口请求还未返回,此时直接调用shipping.filter()相当于对undefined执行方法,直接触发类型错误。你看到console.log(shipping)能输出完整数据,是因为接口返回后组件二次渲染时控制台打印了最新值,但首次渲染的报错已经中断了执行。 - 数据路径不匹配:后端接口返回结构为
{ filterRates: [费率数组] },但前端直接对shipping调用数组方法,实际上真正的费率数组存储在shipping.filterRates字段下,shipping本身是外层对象,不存在filter方法。 - 代码笔误:
ShippingMethodScreen.js首行导入语句写为mport React,缺少首字母i,会直接导致编译失败。
修复方案
前端代码修正
核心是增加加载状态兜底,修正数据取值路径,修复笔误:
// 修正首行笔误,补全i import React, { useState, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { savePaymentMethod } from '../actions/cartActions'; import CheckoutSteps from '../components/CheckoutSteps'; import {detailsShipping} from '../actions/shippingActions'; export default function ShippingMethodScreen(props) { const cart = useSelector((state) => state.cart); const userSignin = useSelector((state) => state.userSignin); const { userInfo } = userSignin; const shippingDetails = useSelector((state) => state.shippingDetails); const { shipping, loading, error } = shippingDetails; const [shippingMethod, setShippingMethod] = useState(''); useEffect(() => { dispatch(detailsShipping(userInfo._id)); }, [dispatch]); // 等数据加载完成、数组存在时再执行过滤逻辑 let cheapest = []; let bestvalue = []; let upsNextDay = []; if (!loading && shipping?.filterRates instanceof Array) { cheapest = shipping.filterRates.filter(rate => rate.attributes.includes('CHEAPEST')); bestvalue = shipping.filterRates.filter(rate => rate.attributes.includes('BESTVALUE')); upsNextDay = shipping.filterRates.filter(rate => rate.servicelevel.token.includes('ups_next_day_air_saver')); } return ( <div> <CheckoutSteps step1 step2 step3></CheckoutSteps> {/* 增加加载、错误状态判断,避免空数据渲染 */} {loading && <div>加载运费选项中...</div>} {error && <div>运费加载失败:{error}</div>} {!loading && !error && ( <div className="shipping-methods"> {/* 遍历cheapest、bestvalue、upsNextDay渲染选项即可 */} </div> )} </div> ); }
可选后端优化
如果不想前端多取一层filterRates字段,可以修改后端返回逻辑,直接返回费率数组,减少嵌套:
// 原代码 res.send({filterRates}); 修改为 res.send(filterRates);
修改后Redux中存储的shipping直接是费率数组,无需再取.filterRates,过滤时直接调用shipping.filter()即可,注意仍需保留初始状态的非空判断。
逻辑验证
从你提供的console打印结果看,费率过滤规则本身没有问题:
- USPS Parcel Select 带有
CHEAPEST属性 - USPS Priority Mail 带有
BESTVALUE属性 - UPS Next Day Air Saver 可以通过
servicelevel.token匹配到
只要解决上述空值和路径问题,即可正常拆分出三类费率。
内容的提问来源于stack exchange,提问作者Gigi101
相关产品推荐
相关产品推荐

