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;

问题原因
- 状态覆盖而非追加:每次调用
setHoursArray([element.startAt])或setHoursArray2([element.startAt])时,都是用单个元素直接覆盖原有数组,导致之前的时段被丢弃,最终只保留最后一个。 - 异步状态更新的误区:
setAvailableDates是异步操作,在第二个then中直接遍历availableDates,此时状态还未更新,拿到的仍是初始空数组。 - 不必要的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
相关产品推荐
相关产品推荐

