前端数据加载过慢求助:代码性能优化方案咨询
优化方案:提升事件统计与组织代码的性能
原代码的性能瓶颈
- 日期格式化重复执行:每次循环日期都调用
toLocaleDateString并做字符串分割替换,属于高频开销操作 - 不必要的重渲染:
useEffect依赖countAndOrganizeEvents,而这个函数每次组件渲染都会重新创建,导致无意义的请求触发 - 数据冗余:每个课程条目重复存储
startProgramDates和endProgramDates,浪费内存 - 日期遍历效率低:对于跨多天的课程,逐天循环的方式在课程周期长时会产生大量迭代
具体优化措施
- 预格式化日期,避免重复计算:把课程的起止日期一次性格式化为目标格式,同时计算日期范围的天数,减少重复的日期处理操作
- 稳定函数引用:用
useCallback包裹countAndOrganizeEvents,避免每次渲染创建新函数,消除不必要的useEffect触发 - 减少数据冗余:只在日期分组的顶层存储
startProgramDates和endProgramDates,课程条目里不再重复存储 - 优化日期范围处理:用
differenceInDays直接计算起止日的天数差,减少逐天调用addDays和判断的开销 - 修正状态读取逻辑:
setEventsCountandDate是异步操作,直接console.log拿不到最新值,改成监听状态变化再打印
优化后的代码
import { useState, useEffect, useCallback } from 'react'; import { parse, addDays, differenceInDays } from 'date-fns'; // 单独提取日期格式化函数,复用逻辑 const formatDateToKey = (date) => { const [day, month, year] = date.toLocaleDateString('en-GB').split('/'); return `${day}-${month}-${year}`; }; const YourComponent = () => { const [eventsCountandDate, setEventsCountandDate] = useState([]); const [daySelected, setDaySelected] = useState(false); // 假设的daySelected状态 // 用useCallback稳定函数引用,避免不必要的重渲染 const countAndOrganizeEvents = useCallback((eventData) => { const coursesByDate = {}; eventData.forEach(({ startProgramDates, endProgramDates, courseName, startTime, endTime, format }) => { const startDate = parse(startProgramDates, 'dd-MM-yyyy', new Date()); const endDate = parse(endProgramDates, 'dd-MM-yyyy', new Date()); const totalDays = differenceInDays(endDate, startDate) + 1; // 包含起止日期 // 预生成该课程覆盖的所有日期key const dateKeys = []; let currentDate = startDate; for (let i = 0; i < totalDays; i++) { dateKeys.push(formatDateToKey(currentDate)); currentDate = addDays(currentDate, 1); } // 批量添加到对应日期分组 dateKeys.forEach(dateKey => { if (!coursesByDate[dateKey]) { coursesByDate[dateKey] = { startProgramDates, endProgramDates, courses: [], }; } coursesByDate[dateKey].courses.push({ courseName, startTime, endTime, format, }); }); }); // 转换为最终需要的数组格式 const coursesCountByDate = Object.entries(coursesByDate).map(([date, { courses, startProgramDates, endProgramDates }]) => ({ date, courseCount: courses.length, startProgramDates, endProgramDates, courses, })); setEventsCountandDate(coursesCountByDate); }, []); useEffect(() => { const fetchData = async () => { try { const response = await axios.get('http://localhost:4000/search-course?date=09-02-2024'); const eventData = response.data.Table1; countAndOrganizeEvents(eventData); } catch (error) { console.error('无法获取事件统计与详情', error); } }; if (daySelected) { fetchData(); } }, [countAndOrganizeEvents, daySelected]); // 监听状态变化,打印最新数据 useEffect(() => { console.log('最新事件数据:', eventsCountandDate); }, [eventsCountandDate]); // 组件其他逻辑... return <div>{/* 组件内容 */}</div>; }; export default YourComponent;
额外优化建议
- 后端层面优化:如果条件允许,让后端直接按日期分组返回数据,彻底减少前端的计算量,这是最有效的性能提升方式
- 日期库轻量化:如果对依赖体积敏感,可以用原生Date API处理日期(比如直接计算时间戳差值),降低第三方库的开销
- 数据缓存:如果相同日期的请求会重复触发,用
useMemo或者本地缓存(如localStorage)存储已处理过的结果,避免重复计算
内容的提问来源于stack exchange,提问作者Pixel
相关产品推荐
相关产品推荐

