React中点击预订按钮后重新渲染slot-id组件的实现方案
解决方案
要实现点击预订按钮后立即更新对应时段的状态,核心是在本地维护已预订的时段ID集合,无需等待API响应即可更新视图,同时处理API请求的成功/失败情况以保证状态一致性。
具体修改步骤:
- 替换全局状态:移除全局的
isOccupied,改用bookedSlots状态存储已预订的时段ID数组(初始为空),独立跟踪每个时段的本地状态。 - 优化预订函数:
- 点击按钮时先将当前时段ID加入
bookedSlots,触发即时视图更新 - 调用预订API,若请求失败则把该时段ID从集合中移除,恢复原状态
- 点击按钮时先将当前时段ID加入
- 调整渲染判断逻辑:时段显示“已占用”的条件为:API返回的
slot.occupied为true,或该时段ID在本地bookedSlots集合中
修改后的完整代码
import React, { useEffect, useState } from 'react' import axios from 'axios' import '../App.css' import { useNavigate } from 'react-router-dom' import { gettingData } from '../api/getUserData' import { handleLogout } from '../api/handleLogout' import { getGroundNear } from '../api/getGroundNearby' import { bookingSlot } from '../api/bookingSlot' const Dashboard = () => { const navigate = useNavigate() const [userData, setUser] = useState(undefined) const [groundData, setGroundData] = useState([]) const [currentTime, setCurrentTime] = useState(Date.now()) // 存储本地已预订的slot ID集合 const [bookedSlots, setBookedSlots] = useState([]) axios.defaults.withCredentials = true; useEffect(() => { gettingData(setUser) }, []) useEffect(() => { console.log("usee 2") if (userData) { console.log(userData) getGroundNear(userData.pincode, 0, 50000, setGroundData) } }, [userData]) const handleBooking = async (slotId, groundId, userId) => { // 先添加到本地集合,立即更新视图 setBookedSlots(prev => [...prev, slotId]) try { // 调用预订API(确保bookingSlot是异步函数,返回Promise) const result = await bookingSlot(slotId, groundId, userId) if (!result) { // API返回失败,回滚本地状态 setBookedSlots(prev => prev.filter(id => id !== slotId)) } } catch (error) { // 请求出错,回滚本地状态 console.error('预订失败:', error) setBookedSlots(prev => prev.filter(id => id !== slotId)) } } return ( <div> <button onClick={() => { handleLogout(navigate) }}>Logout</button> <div> <h3>场地列表</h3> {groundData && groundData.length && groundData?.map((ground) => { return ( <div id='cards' key={ground._id}> <img src={ground.photo} alt='ground'></img> <h4>{ground.ground}</h4> <span>类型: </span><span>{ground.type}</span><br /> <span>{ground.discription}</span> <div className='timings'> <div className='slots'> {ground?.slots?.map(slot => { // 判断时段是否已占用:API标记 或 本地已预订 const isSlotOccupied = slot.occupied || bookedSlots.includes(slot._id) return ( <div id='slot-id' key={slot._id}> {!isSlotOccupied ? ( <button onClick={() => handleBooking(slot._id, slot.ground_id, userData._id)}> {slot.time_start} - {slot.time_end} </button> ) : ( <button id='occupied-slot' style={{ border: '3px dotted red', cursor: 'not-allowed', backgroundColor: '#FF999C' }}> {slot.time_start} - {slot.time_end} </button> )} </div> ) })} </div> </div> </div> ) }) } </div> </div> ) } export default Dashboard
额外提示:
- 确保
bookingSlot是异步函数(返回Promise),否则await逻辑会失效,需检查你的API封装代码 - 给循环渲染的元素添加
key属性(如ground._id和slot._id),符合React最佳实践,避免渲染警告 - API失败时的回滚逻辑可避免本地状态与后端数据不一致的问题
内容的提问来源于stack exchange,提问作者Mohd Arslaan
相关产品推荐
相关产品推荐

