React日历组件首次渲染无法加载数据库数据的问题咨询
日历组件首次渲染无数据,热重载后正常的解决方案
问题描述
开发日历组件,要求日期存在数据库数据时显示对应信息,无数据则为空。当前问题:
- 首次渲染时所有日期框为空,
event值为undefined - 修改代码保存(热重载)后,数据能正常显示
- 之前用
localStorage时,在userListings的useState里用三元表达式初始化(有本地数据则用,否则为空数组)功能正常,想知道数据库场景的解决办法,试过isLoading的三元表达式无效
核心原因
生成日历日期数组的useEffect没有监听userListings的变化:
- 首次渲染时,
userListings初始为空数组,此时生成的days中每个日期的event都是undefined - API请求完成后,
userListings更新,但生成days的逻辑没有重新执行,所以日期框还是空的 - 热重载时,组件重新渲染,此时
userListings已经有数据,生成days时能正确匹配到事件,所以显示正常
解决方案
1. 给生成日历的useEffect添加userListings依赖
确保userListings更新时,重新生成日历日期数组:
useEffect(() => { const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; const today = new Date(); if (nav !== 0) { today.setMonth(new Date().getMonth() + nav); } const month = today.getMonth() const day = today.getDate() const year = today.getFullYear() const firstOfMonth = new Date(year, month, 1); const fullDaysInMonth = new Date(year, month + 1, 0).getDate(); const dateString = firstOfMonth.toLocaleDateString('en-us', { weekday: 'long', year: 'numeric', month: 'numeric', day: 'numeric', }); setDateDisplay(`${today.toLocaleDateString('en-us', {month: 'long'})} ${year}`) let dayWithZ = 0; let monthWithZ = 0; const paddingDays = weekdays.indexOf(dateString.split(',')[0]); const daysArr = []; for (let i = 1; i <= paddingDays + fullDaysInMonth; i++) { if (i - paddingDays < 10) { dayWithZ = ('0' + (i - paddingDays)).slice(-2) } if (i -paddingDays >= 10){ dayWithZ = i-paddingDays; } if ((month + 1) < 10) { monthWithZ = ('0' + (month + 1)).slice(-2) } if ((month + 1) >= 10) { monthWithZ = month + 1; } let dayStringTest = `${year}-${monthWithZ}-${dayWithZ}`; if (i > paddingDays) { daysArr.push({ value: i - paddingDays, // 直接用当前userListings查找,避免闭包问题 event: userListings.find(e => e.date === dayStringTest), isCurrentDay: i - paddingDays === day && nav === 0, date: dayStringTest, }); } else { daysArr.push({ value: 'padding', event: null, isCurrentDay: false, date: '', }); } } setDays(daysArr); }, [setDays, nav, userListings]); // 新增userListings依赖
2. 修复API请求的useEffect依赖
确保currentUser变化时重新请求数据,避免currentUser为空时发起无效请求:
useEffect(() => { async function fetchData() { if (!currentUser) return; // 避免currentUser为空时请求 try { setShowListingsError(false); const res = await fetch(`/api/user/entries/${currentUser._id}`); const data = await res.json(); if (data.success === false) { setShowListingsError(true); return; } setUserListings(data); setIsLoading(false); } catch (error) { setShowListingsError(true); } } fetchData(); }, [currentUser]) // 新增currentUser依赖
3. (可选)优化加载状态显示
如果需要在数据加载完成前显示加载提示,可以在return中判断:
return ( <> {isLoading ? ( <div>加载中...</div> ) : ( <div> <section id="calendar" className="flex flex-wrap"> {days.map((d, index) => ( <Day key={index} day={d} onClick={() => { if (d.value !== 'padding') { setClicked(d.date); } }} /> ))} </section> </div> )} </> )
关于localStorage和数据库的差异
localStorage是同步读取的,可以在useState初始化时直接用三元表达式获取数据;但数据库数据是异步获取的,必须通过useEffect发起请求,待数据返回后更新状态,再触发日历重新渲染,无法在useState初始化时直接获取到异步数据。
内容的提问来源于stack exchange,提问作者liverpool09
相关产品推荐
相关产品推荐

