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

React中Fragment渲染数组状态元素异常:多小时仅显示最后一个

问题:React日历组件时段显示异常,同一日期仅展示最后一个时段

我有一个日历组件,用户点击日期后会获取包含所有可预约日期及对应时段的对象数组(附console.log截图)。在useEffect中处理点击日期的时段,想要将date.startAt的值存入hoursArray状态,但遇到问题:当同一日期存在多个时段时,页面仅显示最后一个时段。

import React, { Component, Fragment, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import axios from "axios";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronRight, faChevronLeft, } from "@fortawesome/free-solid-svg-icons";

import "./c-timeSlot.css";
import "./c-modal.css";
// import '../../hanaa.css';

import dolar from '../../../pictures/charge.png';
import visa from '../../../pictures/PngItem_1162717.png';

const TimeSlot = (props) => {

  const navigate = useNavigate();

  console.log('props time slot', props);
  const day = props.day;
  console.log('slot got ittttttt day', day)
  const docId = props.docId;
  const token = props.token;


  const [availableDates, setAvailableDates] = useState([]);
  const hours = [];
  const hours2 = [];
  const [hoursArray, setHoursArray] = useState(hours);
  const [hoursArray2, setHoursArray2] = useState(hours2);

  const year = '2022-07-';
  var currentDateStr = year.concat(day);

  useEffect(() => {
    setHoursArray([]);
    setHoursArray2([]);
    axios.get(`/doctor/${docId}`,
      {
        headers: {
          "token": token
        }
      }
    ).then(res => {
      console.log('doctor available hours', res);
      async function getCalender() {
        await setAvailableDates(res.data.calender);
      }
      getCalender();
      console.log('available dates ', availableDates);
    }).then(() => {
      availableDates.forEach(element => {
        console.log('currenttttttttt date', currentDateStr);
        console.log(' date', element.date);
        async function findHours() {
          if (element.date == currentDateStr) {
            if (element.startAt.includes('am')) {
              await setHoursArray([element.startAt]);
            } else {
              await setHoursArray2([element.startAt]);
              console.log('array fe l b3denn', hoursArray2);
            }
          }
        }
        findHours();

      })
    })
  }, [day]);


  var sessionType;


  return (
    <>
      <div className="c-bigslots">
        <div>
          <div className="c-MorningSlots">Morning Hours</div>
          <div className="c-slots-up">
            {
              hoursArray.map((hour, index) => (

                <Fragment key={index}>
                  <div className='c-slot'
                  >
                    {hour}
                  </div>

                </Fragment>
              ))}
          </div>

        </div>
        <div>
          <div className="c-EveningSlots">Evening Hours</div>
          <div className="c-slots c-slots_evening">
            {
              hoursArray2.map((hour, index) => (

                <Fragment key={index}>
                  <div className='c-slot'
                  >
                    {hour}
                  </div>

                </Fragment>
              ))}
          </div>

        </div>

      </div>
    </>
  );
}

export default TimeSlot;

availableDates状态数组


问题原因

  1. 状态覆盖而非追加:每次调用setHoursArray([element.startAt])或setHoursArray2([element.startAt])时,都是用单个元素直接覆盖原有数组,导致之前的时段被丢弃,最终只保留最后一个。
  2. 异步状态更新的误区:setAvailableDates是异步操作,在第二个then中直接遍历availableDates,此时状态还未更新,拿到的仍是初始空数组。
  3. 不必要的async/await:状态更新本身不需要用await包裹,这会导致逻辑混乱。

修复方案

直接在请求成功后处理数据,筛选并分类当前日期的时段,一次性更新状态:

import React, { Fragment, useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronRight, faChevronLeft } from "@fortawesome/free-solid-svg-icons";

import "./c-timeSlot.css";
import "./c-modal.css";

import dolar from '../../../pictures/charge.png';
import visa from '../../../pictures/PngItem_1162717.png';

const TimeSlot = (props) => {
  const navigate = useNavigate();
  const { day, docId, token } = props;

  const [availableDates, setAvailableDates] = useState([]);
  const [hoursArray, setHoursArray] = useState([]);
  const [hoursArray2, setHoursArray2] = useState([]);

  const year = '2022-07-';
  const currentDateStr = year.concat(day);

  useEffect(() => {
    // 初始化清空时段数组
    setHoursArray([]);
    setHoursArray2([]);

    axios.get(`/doctor/${docId}`, {
      headers: { "token": token }
    }).then(res => {
      const calendarData = res.data.calender;
      setAvailableDates(calendarData);
      
      // 筛选当前选中日期的所有时段
      const currentDaySlots = calendarData.filter(item => item.date === currentDateStr);
      
      // 分类上午(am)和下午(pm)时段
      const morningSlots = currentDaySlots
        .filter(slot => slot.startAt.includes('am'))
        .map(slot => slot.startAt);
      const eveningSlots = currentDaySlots
        .filter(slot => slot.startAt.includes('pm'))
        .map(slot => slot.startAt);
      
      // 批量更新状态,避免多次覆盖
      setHoursArray(morningSlots);
      setHoursArray2(eveningSlots);
    }).catch(err => {
      console.error('获取医生可预约时段失败:', err);
    });
  }, [day, docId, token]); // 添加依赖项,确保props变化时重新执行

  return (
    <>
      <div className="c-bigslots">
        <div>
          <div className="c-MorningSlots">Morning Hours</div>
          <div className="c-slots-up">
            {hoursArray.map((hour, index) => (
              <Fragment key={index}>
                <div className='c-slot'>{hour}</div>
              </Fragment>
            ))}
          </div>
        </div>
        <div>
          <div className="c-EveningSlots">Evening Hours</div>
          <div className="c-slots c-slots_evening">
            {hoursArray2.map((hour, index) => (
              <Fragment key={index}>
                <div className='c-slot'>{hour}</div>
              </Fragment>
            ))}
          </div>
        </div>
      </div>
    </>
  );
}

export default TimeSlot;

关键优化点

  • 直接处理响应数据:在请求成功后立即处理时段分类,无需依赖状态更新后的异步值,避免数据不同步问题。
  • 批量更新状态:用数组filter和map生成完整的时段数组后,一次性更新状态,彻底解决覆盖问题。
  • 完善依赖项:在useEffect的依赖数组中添加docId和token,确保这些值变化时重新请求数据。
  • 添加错误捕获:处理请求失败的情况,便于调试。
  • 简化代码结构:解构props、移除不必要的async函数,让代码更简洁易读。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:51:22