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

React日历组件函数调用报错(无效钩子调用)及日期格式转换问题排查

解决React日历组件的钩子调用错误与日期格式转换问题

咱们先一步步拆解并解决你遇到的两个问题:

一、「无效钩子调用」错误的原因与修复

这个错误是因为你违反了React Hook的核心规则:所有Hook必须在组件/自定义Hook的顶层作用域调用,绝对不能在事件处理函数(比如handleChange)、循环、条件语句里使用Hook。

你之前在handleChange里直接调用了useSWR,这完全不符合规则。正确的做法是:让useSWR依赖日期状态,当日期变化时自动触发重新请求,而handleChange只负责更新日期状态。

修改后的useAnalytics代码:

import useSWR from "swr";
import { useState } from "react";
import { apiRequest } from "../../../util/util";

export default function useAnalytics() {
  // 初始化3个月前的日期(补全之前缺失的变量声明)
  const d = new Date();
  d.setMonth(d.getMonth() - 3);
  
  const [isLoading, setIsLoading] = useState(false);
  // 初始状态存储Date对象,方便后续转换
  const [dateRange, setDateRange] = useState([d, new Date()]);
  const [startDate, endDate] = dateRange;

  // handleChange只负责更新日期范围,不做其他逻辑
  const handleChange = (newDateRange) => {
    setDateRange(newDateRange);
  };

  // 把useSWR放在Hook顶层,依赖startDate/endDate,日期变化时自动重新请求
  const { data: sentimentData } = useSWR(
    // 在这里把Date对象转成接口需要的时间戳
    `xx/xx/xxx-xx-xx?startTime=${startDate.getTime()}&endTime=${endDate.getTime()}`,
    fetchSentiment
  );

  // 封装请求函数,配合isLoading状态
  async function fetchSentiment(url) {
    setIsLoading(true);
    try {
      return await apiRequest(url);
    } finally {
      setIsLoading(false);
    }
  }

  return {
    sentimentData, 
    handleChange, 
    startDate, 
    endDate,
    isLoading
  };
}

二、日期格式转换为时间戳的正确方式

你之前的转换代码有两个问题:

  1. setDateRange是异步操作,不能在调用后立刻使用dateRange的新值;
  2. 语法错误,setDateRange只接收一个参数,而且不需要用Date()包裹已有Date对象。

React DatePicker返回的是标准Date对象,直接调用dateObj.getTime()就能获取毫秒级时间戳,如果接口需要秒级时间戳,就用Math.floor(dateObj.getTime() / 1000)。

两种实现方案:

方案1:状态存Date对象,请求时转换

就是上面修改后的代码,状态里保留Date对象,在拼接接口URL时调用getTime()转换,好处是保留了Date对象的灵活性,方便后续其他场景使用。

方案2:状态直接存时间戳

如果你的业务只需要时间戳,可以在handleChange里直接转换后存储:

const handleChange = (newDateRange) => {
  // 把Date数组转成时间戳数组再存状态
  const [start, end] = newDateRange;
  setDateRange([start.getTime(), end.getTime()]);
};

// 对应的初始状态也要改成时间戳
const [dateRange, setDateRange] = useState([d.getTime(), new Date().getTime()]);
const [startDate, endDate] = dateRange;

// 此时拼接URL时直接用startDate/endDate即可
const { data: sentimentData } = useSWR(
  `xx/xx/xxx-xx-xx?startTime=${startDate}&endTime=${endDate}`,
  fetchSentiment
);

这样修改后,日期变更时会自动触发SWR重新请求,接口也能拿到正确格式的时间戳参数了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 10:27:39