基于时长限制优化日历任务分配及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
相关产品推荐
相关产品推荐

