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
相关产品推荐
相关产品推荐

