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 }; }
二、日期格式转换为时间戳的正确方式
你之前的转换代码有两个问题:
setDateRange是异步操作,不能在调用后立刻使用dateRange的新值;- 语法错误,
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
相关产品推荐
相关产品推荐

