React Native预约App:选择日期后已预约时间按钮未置灰求助
React Native预约App:日期切换后已预约时间按钮不更新状态的修复方案
核心问题分析
- 参数传递错误:点击场地卡片时,传递给
handleImageClick的是字符串类型的场地文档ID,但函数内部错误地尝试访问selectedFieldId?.id_lapangan属性,导致Firestore查询条件无效,无法获取对应场地的预约数据,bookingData始终为空,无法判断时间是否被预约。 - 日期变化未触发状态更新:切换日期后,没有重新筛选或请求对应日期的预约数据,组件无法更新时间按钮的状态。
修复步骤
1. 修复场地ID的查询参数
修改handleImageClick函数,直接使用传入的场地ID作为查询条件,同时保存当前选中的场地ID,用于后续日期切换时重新查询:
const handleImageClick = async (selectedFieldId: any) => { try { const querySnapshot = await firestore() .collection('booking') .where('id_lapangan', '==', selectedFieldId) // 移除多余的?.id_lapangan .get(); const bookings: any = querySnapshot.docs.map(doc => doc.data()); setBookingData(bookings); setSelectedTime(null); setSelectedFieldId(selectedFieldId); // 保存当前选中场地ID console.log('Data booking :', bookings); } catch (error) { console.log('Error fetching booking data:', error); } };
2. 日期切换时重新请求对应场地的预约数据
在handleDateChange函数中添加逻辑,当日期切换且已有选中场地时,拉取该场地对应日期的预约数据(添加日期范围过滤,减少数据传输量):
const handleDateChange = async (event: any, selectedDate: any) => { const currentDate = selectedDate || date; setShowDatePicker(false); const selectedDateTime = moment(currentDate).tz('Asia/Singapore'); const selectedDateOnly = selectedDateTime.format('YYYY-MM-DD'); const today = moment().tz('Asia/Singapore'); const normalizedCurrentDate = moment(selectedDateOnly).startOf('day'); const normalizedToday = moment(today).tz('Asia/Singapore').startOf('day'); if (normalizedCurrentDate.isBefore(normalizedToday)) { Alert.alert('Tanggal tidak valid', 'Tolong pilih tanggal yang valid'); return; } setDate(selectedDateTime.toDate()); // 若已选中场地,重新拉取对应日期的预约数据 if (selectedFieldId) { try { const startOfDay = moment(selectedDateOnly).startOf('day').tz('Asia/Singapore').toDate(); const endOfDay = moment(selectedDateOnly).endOf('day').tz('Asia/Singapore').toDate(); const querySnapshot = await firestore() .collection('booking') .where('id_lapangan', '==', selectedFieldId) .where('waktu', '>=', startOfDay) .where('waktu', '<=', endOfDay) .get(); const bookings: any = querySnapshot.docs.map(doc => doc.data()); setBookingData(bookings); } catch (error) { console.log('Error fetching booking data on date change:', error); } } };
3. 优化时间预约状态的判断逻辑
确保日期和小时的匹配逻辑准确处理时区,避免因格式不一致导致的匹配失败:
const isTimeBooked = bookingData.find( booking => { const bookingDate = moment(booking.waktu).tz('Asia/Singapore').format('YYYY-MM-DD'); const selectedDateStr = moment(date).tz('Asia/Singapore').format('YYYY-MM-DD'); const bookingHour = moment(booking.waktu).tz('Asia/Singapore').hours(); return bookingDate === selectedDateStr && bookingHour === time.getHours(); } );
修改后的关键代码片段
const ScheduleScreen = () => { // 保留原有状态,确保selectedFieldId已定义 const [selectedFieldId, setSelectedFieldId] = useState(null); // ... 其他原有函数 const handleImageClick = async (selectedFieldId: any) => { try { const querySnapshot = await firestore() .collection('booking') .where('id_lapangan', '==', selectedFieldId) .get(); const bookings: any = querySnapshot.docs.map(doc => doc.data()); setBookingData(bookings); setSelectedTime(null); setSelectedFieldId(selectedFieldId); console.log('Data booking :', bookings); } catch (error) { console.log('Error fetching booking data:', error); } }; const handleDateChange = async (event: any, selectedDate: any) => { const currentDate = selectedDate || date; setShowDatePicker(false); const selectedDateTime = moment(currentDate).tz('Asia/Singapore'); const selectedDateOnly = selectedDateTime.format('YYYY-MM-DD'); const today = moment().tz('Asia/Singapore'); const normalizedCurrentDate = moment(selectedDateOnly).startOf('day'); const normalizedToday = moment(today).tz('Asia/Singapore').startOf('day'); if (normalizedCurrentDate.isBefore(normalizedToday)) { Alert.alert('Tanggal tidak valid', 'Tolong pilih tanggal yang valid'); return; } setDate(selectedDateTime.toDate()); if (selectedFieldId) { try { const startOfDay = moment(selectedDateOnly).startOf('day').tz('Asia/Singapore').toDate(); const endOfDay = moment(selectedDateOnly).endOf('day').tz('Asia/Singapore').toDate(); const querySnapshot = await firestore() .collection('booking') .where('id_lapangan', '==', selectedFieldId) .where('waktu', '>=', startOfDay) .where('waktu', '<=', endOfDay) .get(); const bookings: any = querySnapshot.docs.map(doc => doc.data()); setBookingData(bookings); } catch (error) { console.log('Error fetching booking data on date change:', error); } } }; return ( // ... 原有渲染结构不变 <View style={styles.buttonContainer}> {Array.from(Array(4), (_, row) => ( <View style={styles.row} key={`row_${row}`}> {Array.from(Array(row === 0 || row === 3 ? 3 : 4), (_, col) => { let index; if (row === 0) index = col; else if (row === 1) index = 3 + col; else if (row === 2) index = 7 + col; else if (row === 3) index = 11 + col; if (index < availableTimes.length) { const time = availableTimes[index]; const isTimeBooked = bookingData.find( booking => { const bookingDate = moment(booking.waktu).tz('Asia/Singapore').format('YYYY-MM-DD'); const selectedDateStr = moment(date).tz('Asia/Singapore').format('YYYY-MM-DD'); const bookingHour = moment(booking.waktu).tz('Asia/Singapore').hours(); return bookingDate === selectedDateStr && bookingHour === time.getHours(); } ); return ( <TouchableWithoutFeedback key={`button_${index}`} onPress={() => setSelectedTime(time)}> <View style={[ styles.button, isTimeBooked ? styles.buttonUnavailable : null, selectedTime === time ? styles.buttonSelected : null ]}> <Text style={styles.buttonText}> {time.getHours()}:00 </Text> </View> </TouchableWithoutFeedback> ); } return null; })} </View> ))} </View> // ... 原有渲染结构不变 ); };
内容的提问来源于stack exchange,提问作者Jonathan Laala
相关产品推荐
相关产品推荐

