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

FullCalendar React中eventClick时useState设置event.id失效求助

问题解决指南

一、setEventId 赋值异常问题

1. 修正状态初始值类型

你将eventId初始化为数组useState([]),但实际要存储的是单个事件ID(字符串/数字类型),类型不匹配会导致状态更新异常。修改初始值为null或undefined:

const[eventId, setEventId] = useState(null)

2. 理解React setState的异步特性

调用setEventId后,不能立即获取到新的state值——React的状态更新是异步批量处理的,你看到的console.log(eventId)输出旧值是正常现象。如果需要在状态更新后执行逻辑,用useEffect监听eventId的变化:

useEffect(() => {
  if (eventId !== null) {
    // 这里可以使用最新的eventId,比如打开模态框、请求事件详情等
    console.log("最新的eventId:", eventId)
    setIsModalOpen(true)
  }
}, [eventId])

二、点击事件触发日历重复拉取数据问题

1. 禁止直接修改state对象

在getEventsData中,你直接修改了urlParms.start的属性:urlParms.start.setDate(0),这违反了React状态不可变的原则,会导致urlParms引用未变但内部属性被篡改,触发useEffect不必要的执行。应该创建新的日期对象和参数对象:

const getEventsData = async function () {
  setLoading(true)
  // 创建新的日期对象,避免修改原state
  const startDate = new Date(urlParms.start)
  startDate.setDate(0)
  try {
    const response = await axiosAPI.get(`${URL}/?start=${startDate.toISOString()}&end=${urlParms.end}`)
    if (response?.data) {
        setEvents(response.data)
    }
  } catch (error) {
      console.log(error)
      setError("加载事件失败")
  } finally {
      setLoading(false) // 无论成功失败都关闭loading状态
  }
}

2. 优化参数更新逻辑

确保urlParms的更新始终通过setUrlParms创建新对象,而非直接修改原对象。比如更新日期范围时:

// 示例:正确更新日期范围的方式
const updateDateRange = (newStart, newEnd) => {
  setUrlParms({
    start: new Date(newStart),
    end: newEnd.toISOString()
  })
}

3. 简化事件传递逻辑

你的reservations useMemo没有实际过滤逻辑,可直接移除,将FullCalendar的events属性直接绑定到events状态,减少不必要的memo计算:

<FullCalendar
  // 其他配置
  events={events}
  eventClick={handleEventClick}
/>

4. 防止FullCalendar不必要重渲染

如果上述修改后仍有重渲染问题,用useCallback包裹handleEventClick,避免每次渲染创建新函数:

const handleEventClick = useCallback((calData) => {
  console.log("当前点击的事件ID:", calData.event.id)
  setEventId(calData.event.id)
}, [])

完整修正后的核心代码片段

const Calendar = () => {
  const[URL, setURL] = useState("events")
  const[error, setError] = useState("")
  const[loading, setLoading] = useState(false)
  const[isModalOpen, setIsModalOpen] = useState(false)
  const[eventId, setEventId] = useState(null) // 修正初始值类型
  const[events, setEvents] = useState([])

  const[urlParms, setUrlParms] = useState({
    start: new Date(),
    end: new Date().toISOString(),
  })

  useEffect(() => {
    getEventsData()
  }, [URL, urlParms])

  const getEventsData = async function () {
    setLoading(true)
    const startDate = new Date(urlParms.start)
    startDate.setDate(0)
    try {
      const response = await axiosAPI.get(`${URL}/?start=${startDate.toISOString()}&end=${urlParms.end}`)
      if (response?.data) {
          setEvents(response.data)
      }
    } catch (error) {
        console.log(error)
        setError("加载事件失败")
    } finally {
        setLoading(false)
    }
  }

  const handleEventClick = useCallback((calData) => {
    console.log("当前点击的事件ID:", calData.event.id)
    setEventId(calData.event.id)
  }, [])

  useEffect(() => {
    if (eventId !== null) {
      setIsModalOpen(true)
      console.log("最新的eventId:", eventId)
    }
  }, [eventId])

  return (
    <div>
     <FullCalendar
      /* 其他基础配置已省略 */
       events={events}
       eventClick={handleEventClick}
     />
     {/* 模态框组件 */}
     <Modal show={isModalOpen} onHide={() => setIsModalOpen(false)}>
       {/* 模态框内容,可使用eventId请求事件详情 */}
     </Modal>
    </div>
   )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:35:15