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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:28:09