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

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

修改说明

  1. 封装时间计算逻辑:把截止时间和配送日期的计算抽成独立函数,提高代码复用性和可维护性
  2. 添加定时检查:用setInterval每分钟重新计算一次时间状态,确保非倒计时结束的时间节点也能正确更新
  3. 监听倒计时完成事件:通过onComplete回调在倒计时结束时立即更新状态
  4. 实时获取时间标记:在renderer内部调用函数获取最新的时间状态,避免顶层变量不更新的问题
  5. 优化useEffect依赖:仅依赖cutoffhour,避免不必要的重渲染

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 19:35:20