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

基于时长限制优化日历任务分配及React代码无限循环排查

日历应用任务分配优化与React无限循环修复

需求说明

这是一款日历应用,核心功能与规则如下:

  • 用户可通过下拉菜单选择每日任务时长上限,可选值为2小时(120分钟)、4小时(240分钟)、6小时(360分钟)
  • 给定包含duration(分钟)属性的任务数组,需从当前日期开始分配任务,尽可能多地将任务安排到日历中,确保每日任务总时长不超过所选上限
  • 分配示例:任务时长数组为[50,40,20,60,50,20,30,45,45],选择2小时上限时,分配结果为:
    • 当前日期:50、40、20(总110分钟)
    • 下一日期:60、50(总110分钟)
    • 下一日期:20、30、45(总95分钟)
    • 下一日期:45(总45分钟)

无限循环问题定位

原代码出现无限循环的核心原因:

  • 在组件渲染阶段直接调用getTasks生成分配结果,且未对结果做缓存处理
  • getTasks每次调用都会返回全新的数组/对象引用,导致React判定组件状态发生变化,触发重新渲染;重新渲染又会再次调用getTasks,形成死循环

修复与优化方案

1. 修复无限循环:用useMemo缓存计算结果

通过React的useMemo钩子缓存任务分配结果,仅当任务数组或每日上限发生变化时,才重新执行分配逻辑,避免不必要的重复计算和渲染。

2. 优化任务分配逻辑(贪心算法实现)

采用顺序累加的贪心策略,确保在不超每日上限的前提下,尽可能多地分配任务:

  • 初始化当前日期的剩余时长为每日上限
  • 遍历任务数组,若当前任务能加入当前日期(剩余时长足够)则直接添加,否则开启新日期存放任务

修复后的代码示例

import { useState, useMemo } from 'react';

const Calendar = () => {
  const [dailyLimit, setDailyLimit] = useState(120); // 默认2小时
  const tasks = [
    { duration: 50 },
    { duration: 40 },
    { duration: 20 },
    { duration: 60 },
    { duration: 50 },
    { duration: 20 },
    { duration: 30 },
    { duration: 45 },
    { duration: 45 }
  ];

  // 用useMemo缓存任务分配结果,仅当tasks或dailyLimit变化时重新计算
  const assignedTasks = useMemo(() => {
    const result = [];
    let currentDayTasks = [];
    let currentDayTotal = 0;

    for (const task of tasks) {
      if (currentDayTotal + task.duration <= dailyLimit) {
        currentDayTasks.push(task);
        currentDayTotal += task.duration;
      } else {
        // 当前日期已满,存入结果并开启新日期
        result.push(currentDayTasks);
        currentDayTasks = [task];
        currentDayTotal = task.duration;
      }
    }

    // 加入最后一个日期的任务
    if (currentDayTasks.length > 0) {
      result.push(currentDayTasks);
    }

    return result;
  }, [tasks, dailyLimit]);

  return (
    <div>
      <select
        value={dailyLimit}
        onChange={(e) => setDailyLimit(Number(e.target.value))}
      >
        <option value={120}>2小时</option>
        <option value={240}>4小时</option>
        <option value={360}>6小时</option>
      </select>
      <div className="calendar">
        {assignedTasks.map((dayTasks, index) => (
          <div key={index} className="day">
            <h3>
              {index === 0 ? '当前日期' : `第${index + 1}个日期`}
            </h3>
            <ul>
              {dayTasks.map((task, taskIndex) => (
                <li key={taskIndex}>{task.duration}分钟</li>
              ))}
            </ul>
            <p>总时长:{dayTasks.reduce((sum, t) => sum + t.duration, 0)}分钟</p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Calendar;

关键说明

  • useMemo的依赖数组[tasks, dailyLimit]确保只有当任务数组或每日上限变更时,才重新计算分配结果,从根源上切断无限循环
  • 贪心分配逻辑完全符合需求中的示例结果,保证了任务分配的合理性与高效性

内容的提问来源于stack exchange,提问作者user20926543

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 02:37:30