React中useEffect无法自动更新deliveryDate状态,需刷新页面
问题
我用dayjs和react-countdown组件实现了一个倒计时器,要求在特定截止时间(下午4点)后自动更新配送日期。目前功能仅在页面刷新时生效,useEffect无法自动更新deliveryDate状态,希望倒计时结束后能自动更新配送日期。
解决方案
核心问题分析
useEffect未设置依赖数组,仅在组件挂载时执行一次,后续时间推移不会触发重新计算- 未监听react-countdown的
completed状态,倒计时结束后无法自动触发状态更新 - 顶层定义的
now、isSaturday等变量不会随组件渲染实时更新当前时间
修改后的完整代码
import React, { useEffect, useState } from 'react' import Countdown from 'react-countdown' import dayjs from 'dayjs' const FulfilmentDelivery = ({ cutoffhour }) => { const [cutoffTime, setCutoffTime] = useState(() => calculateCutoffTime(cutoffhour)) const [deliveryDate, setDeliveryDate] = useState(() => calculateDeliveryDate(cutoffhour)) // 封装截止时间计算逻辑 function calculateCutoffTime(cutoff) { const now = dayjs() const isSaturday = now.day() === 6 const isSunday = now.day() === 0 const isFridayAfterCutoff = now.day() === 5 && now.hour() >= cutoff const isThursdayAfterCutoff = now.day() === 4 && now.hour() >= cutoff if (now.hour() >= cutoff && !isFridayAfterCutoff && !isSaturday && !isSunday) { return now.add(1, 'day').hour(cutoff).minute(0).second(0) } else if (isThursdayAfterCutoff) { return now.add(4, 'day').hour(cutoff).minute(0).second(0) } else if (now.day() === 5 && now.hour() < cutoff) { return now.add(3, 'day').hour(cutoff).minute(0).second(0) } else if (isSaturday) { return now.add(3, 'day').hour(cutoff).minute(0).second(0) } else if (isSunday) { return now.add(2, 'day').hour(cutoff).minute(0).second(0) } return now.add(1, 'day').hour(cutoff).minute(0).second(0) } // 封装配送日期计算逻辑 function calculateDeliveryDate(cutoff) { const now = dayjs() const isSaturday = now.day() === 6 const isSunday = now.day() === 0 const isFridayAfterCutoff = now.day() === 5 && now.hour() >= cutoff const isThursdayAfterCutoff = now.day() === 4 && now.hour() >= cutoff if (now.hour() >= cutoff && !isFridayAfterCutoff && !isSaturday && !isSunday) { return now.add(2, 'day').format('dddd D MMM') } else if (isThursdayAfterCutoff) { return now.add(4, 'day').format('dddd D MMM') } else if (now.day() === 5 && now.hour() < cutoff) { return now.add(3, 'day').format('dddd D MMM') } else if (isSaturday) { return now.add(3, 'day').format('dddd D MMM') } else if (isSunday) { return now.add(2, 'day').format('dddd D MMM') } else if (isFridayAfterCutoff) { return now.add(4, 'day').format('dddd D MMM') } return now.add(1, 'day').format('dddd D MMM') } // 定时检查时间变化,每分钟更新一次 useEffect(() => { const timer = setInterval(() => { const newCutoffTime = calculateCutoffTime(cutoffhour) const newDeliveryDate = calculateDeliveryDate(cutoffhour) setCutoffTime(newCutoffTime) setDeliveryDate(newDeliveryDate) }, 60000) return () => clearInterval(timer) }, [cutoffhour]) // 倒计时完成时立即更新状态 const handleCountdownComplete = () => { const newCutoffTime = calculateCutoffTime(cutoffhour) const newDeliveryDate = calculateDeliveryDate(cutoffhour) setCutoffTime(newCutoffTime) setDeliveryDate(newDeliveryDate) } const getCurrentTimeFlags = () => { const now = dayjs() return { isSaturday: now.day() === 6, isSunday: now.day() === 0, cutoffFriday: now.day() === 5 && now.hour() >= cutoffhour } } return ( <div className="align-items-center d-flex h-100"> <span className="display-5" data-icon="z"></span> <div className="ps-2 w-100"> <Countdown date={cutoffTime} onComplete={handleCountdownComplete} renderer={({ hours, minutes, seconds, completed }) => { const { isSaturday, isSunday, cutoffFriday } = getCurrentTimeFlags() if (cutoffFriday || isSaturday || isSunday) { return ( <> <span className="fw-bold fs-6">Order now</span>{' '} <span>for delivery on {deliveryDate}</span> </> ) } return ( <> <span className="fw-bold fs-6">Order within</span>{' '} <span className="text-danger fw-bold fs-6"> {`${hours >= 1 ? `${hours} hrs ` : ``}${ minutes >= 1 ? `${minutes} mins` : `` }${seconds >= 1 ? ` ${seconds} sec` : ``}`} </span> <br /> for delivery on {deliveryDate} </> ) }} /> </div> </div> ) } export default FulfilmentDelivery
修改说明
- 封装时间计算逻辑:把截止时间和配送日期的计算抽成独立函数,提高代码复用性和可维护性
- 添加定时检查:用
setInterval每分钟重新计算一次时间状态,确保非倒计时结束的时间节点也能正确更新 - 监听倒计时完成事件:通过
onComplete回调在倒计时结束时立即更新状态 - 实时获取时间标记:在renderer内部调用函数获取最新的时间状态,避免顶层变量不更新的问题
- 优化useEffect依赖:仅依赖
cutoffhour,避免不必要的重渲染
内容的提问来源于stack exchange,提问作者purpleorangepeach
相关产品推荐
相关产品推荐

