React大屏仪表盘午夜零点无法自动更新日期跳转下一天解决方案问询
大屏仪表盘午夜自动更新日期解决方案
原方案存在的问题
- 整点触发逻辑不可靠:每秒判断时间是否严格等于
00:00:00,如果JS主线程出现阻塞、页面休眠、卡帧等情况,会错过这个时间点,导致永远无法触发更新 - 状态无自动更新逻辑:Context的
initialState仅在应用首次初始化时计算一次,没有后续的更新逻辑 - 强制刷新页面体验差:大屏展示场景下 reload 会出现短暂白屏,影响展示效果
- 原reducer代码存在语法错误:
startDate和endDate定义末尾多了多余的分号
最优实现方案(无刷新更新,性能最优)
不需要刷新页面,通过更新Context状态实现日期自动切换,同时避免每秒轮询的性能损耗。
第一步:修改reducers.js,新增日期更新逻辑
import moment from "moment"; export const initialState = { startDate: moment().startOf("day").local(), endDate: moment().endOf("day").local(), } export const reducer = (state, action) => { switch (action.type) { case 'UPDATE_DATE': return { ...state, startDate: moment().startOf("day").local(), endDate: moment().endOf("day").local(), } default: return state } }
第二步:修改UpdateDate组件,替换轮询逻辑为精准倒计时
计算当前时间到下一次零点的时间差,使用setTimeout一次性触发更新,同时监听页面可见性变化,避免页面休眠导致的倒计时不准问题。
import React, { useEffect } from 'react' import moment from "moment"; function UpdateDate() { const [{ startDate, endDate }, dispatch] = useStateValue(); // 计算到下一次零点的毫秒数 const getMillisecondsToMidnight = () => { const now = moment(); const midnight = moment().add(1, 'day').startOf('day'); return midnight.diff(now); } useEffect(() => { let dateUpdateTimer; const scheduleDateUpdate = () => { // 清除已有定时器 if (dateUpdateTimer) clearTimeout(dateUpdateTimer); // 设置下一次零点的更新定时器 dateUpdateTimer = setTimeout(() => { // 触发Context更新日期 dispatch({ type: 'UPDATE_DATE' }); // 重新安排下一天的更新 scheduleDateUpdate(); }, getMillisecondsToMidnight()); } // 页面从后台切回时重新计算倒计时,避免休眠导致的误差 const handleVisibilityChange = () => { if (!document.hidden) { scheduleDateUpdate(); } } scheduleDateUpdate(); document.addEventListener('visibilitychange', handleVisibilityChange); return () => { clearTimeout(dateUpdateTimer); document.removeEventListener('visibilitychange', handleVisibilityChange); } }, [dispatch]) const url=`http:domain/live-dashboard?from=${startDate}&to=${endDate}`; return ( <div> <iframe className="embed-responsive-item" src={url} ></iframe> </div> ) } export default UpdateDate;
降级方案(必须刷新页面的优化版)
如果业务场景必须要刷新页面,优化原有判断逻辑,避免错过零点时间点:
useEffect(() => { // 记录今天的日期,避免同一天多次触发刷新 let lastUpdatedDate = moment().format('YYYY-MM-DD'); const daterollOver = setInterval(function () { const currentDate = moment().format('YYYY-MM-DD'); if (currentDate !== lastUpdatedDate) { lastUpdatedDate = currentDate; window.location.reload(); } }, 1000 * 30); // 每30秒检查一次即可,性能更好 return () => { clearInterval(daterollOver); } }, [])
内容的提问来源于stack exchange,提问作者MPK
相关产品推荐
相关产品推荐

