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

React日历组件首次渲染无法加载数据库数据的问题咨询

日历组件首次渲染无数据,热重载后正常的解决方案

问题描述

开发日历组件,要求日期存在数据库数据时显示对应信息,无数据则为空。当前问题:

  • 首次渲染时所有日期框为空,event值为undefined
  • 修改代码保存(热重载)后,数据能正常显示
  • 之前用localStorage时,在userListings的useState里用三元表达式初始化(有本地数据则用,否则为空数组)功能正常,想知道数据库场景的解决办法,试过isLoading的三元表达式无效

核心原因

生成日历日期数组的useEffect没有监听userListings的变化:

  1. 首次渲染时,userListings初始为空数组,此时生成的days中每个日期的event都是undefined
  2. API请求完成后,userListings更新,但生成days的逻辑没有重新执行,所以日期框还是空的
  3. 热重载时,组件重新渲染,此时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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:25:06