React Native状态钩子报错+UI卡顿:折扣按周分组逻辑优化求助
问题分析与优化方案
我来帮你拆解并解决遇到的几个核心问题:函数报错、UI卡顿,同时优化你的按星期分组折扣的逻辑。
1. 先解决「getVenueDiscounts is not a function」报错
你把getVenueDiscounts()作为useState的初始值,但JS是从上到下执行的——此时getVenueDiscounts函数还没被定义,自然会抛出这个错误。
有两个简单的解决办法:
- 把
getVenueDiscounts函数移到useState声明的前面; - 给
useState传一个回调函数(更推荐,避免初始渲染就执行 heavy 计算):
这种方式只会在组件首次挂载时执行一次计算,后续渲染不会重复触发。const [weekDiscounts, setWeekDiscounts] = useState(() => getVenueDiscounts());
2. 优化按星期分组的业务逻辑
你的嵌套循环+大量if-else不仅代码冗余,可读性差,还可能带来不必要的性能开销。这里提供两种优化方案,包括用lodash的简化版本:
方案1:纯JS简化(无需额外依赖)
先建立dayId到数组索引的映射表,然后通过两次遍历完成分组,彻底去掉冗余的条件判断:
const getVenueDiscounts = () => { // 初始化7个空数组的结果容器 const weekDiscountsCopy = Array.from({ length: 7 }, () => []); // 建立dayId到数组索引的映射(dayId 1-7对应索引0-6) const dayIndexMap = { 1:0, 2:1, 3:2, 4:3, 5:4, 6:5, 7:6 }; // 如果没有折扣,直接返回初始数组 if (!venueStore.myDiscounts.length) return weekDiscountsCopy; // 深拷贝折扣列表(如果不需要修改原数据,可省略深拷贝) const allDiscounts = _.cloneDeep(venueStore.myDiscounts); allDiscounts.forEach(discount => { discount.days.forEach(day => { const targetIndex = dayIndexMap[day.id]; // 确保day.id是有效范围,避免数组越界 if (typeof targetIndex === 'number') { weekDiscountsCopy[targetIndex].push(discount); } }); }); setDiscounts(allDiscounts); return weekDiscountsCopy; };
方案2:用lodash进一步简化(代码更简洁)
利用lodash的flatMap和groupBy工具函数,把分组逻辑拆解得更清晰:
const getVenueDiscounts = () => { const weekDiscountsCopy = Array.from({ length: 7 }, () => []); const dayIndexMap = { 1:0, 2:1, 3:2, 4:3, 5:4, 6:5, 7:6 }; if (!venueStore.myDiscounts.length) return weekDiscountsCopy; const allDiscounts = _.cloneDeep(venueStore.myDiscounts); // 先把每个折扣和对应的dayId配对,扁平化处理 const discountDayPairs = _.flatMap(allDiscounts, discount => discount.days.map(day => ({ ...discount, targetDayId: day.id })) ); // 按dayId分组 const groupedByDay = _.groupBy(discountDayPairs, 'targetDayId'); // 将分组结果填充到对应星期的数组中,并去重(同一个折扣可能对应多天) Object.entries(groupedByDay).forEach(([dayId, discounts]) => { const targetIndex = dayIndexMap[dayId]; if (typeof targetIndex === 'number') { weekDiscountsCopy[targetIndex] = _.uniqBy(discounts, 'id'); } }); setDiscounts(allDiscounts); return weekDiscountsCopy; };
3. 解决UI卡顿问题
之前用空依赖useEffect还是卡顿,大概率是因为每次渲染都重复执行了计算逻辑。推荐用useMemo缓存计算结果,只有当依赖项变化时才重新计算:
// 用useMemo缓存计算结果,避免无意义的重复计算 const weekDiscounts = useMemo(() => { const weekDiscountsCopy = Array.from({ length: 7 }, () => []); const dayIndexMap = { 1:0, 2:1, 3:2, 4:3, 5:4, 6:5, 7:6 }; if (!venueStore.myDiscounts.length) return weekDiscountsCopy; const allDiscounts = _.cloneDeep(venueStore.myDiscounts); allDiscounts.forEach(discount => { discount.days.forEach(day => { const targetIndex = dayIndexMap[day.id]; if (typeof targetIndex === 'number') { weekDiscountsCopy[targetIndex].push(discount); } }); }); return weekDiscountsCopy; }, [venueStore.myDiscounts]); // 只有当myDiscounts变化时,才重新计算 // 单独用useEffect更新discounts状态,避免循环渲染 useEffect(() => { if (venueStore.myDiscounts.length) { setDiscounts(_.cloneDeep(venueStore.myDiscounts)); } }, [venueStore.myDiscounts]);
注意:不要在useMemo里调用setDiscounts,这会触发组件重复渲染,形成循环更新。把状态更新放到单独的useEffect里,只在依赖项变化时执行一次。
内容的提问来源于stack exchange,提问作者gabogabans
相关产品推荐
相关产品推荐

